Race condition in js/jquery when/done sequence?
===

I have a web applciation based on apache, php, js/jquery. One module of the application is initialized when the document is loaded. That sequence calls an init() funcion that performs a number of tasks, amongst others it fetches two html dialogs via ajax and inserts them into the existing page. A reference to those dialogs is saved as shortcuts, so that I don't have to specify jquery selectors throughout my scripts but can simply use those shortcuts instead. This work fine, except that there are very few cases (now and then...) when the shortcuts are 'undefined' when trying to bind a handler to an element inside the fetched dialogs. Which is odd, because apart from that bind the dialogs are usable throughout the application. This suggests that the ajax calls succeed, but aparently there is some kind of race condition, so that now and then the shortcuts are only set _after_ the bind attempt. 

In my understanding this should not happen, since the bind is done in the .done() part of a when() and should only be executed after the ajax retrieval of the dialogs has finished inside the when(). 

Aparently I am missing something fundamental here. Anyone got a hint for me ? 


The following cites code excerpts from the working implementation. They may appear syntactically invalid as some parts, but that is just due to the removal of code parts not relevant here. The unshortened code works fine. 

The shortcuts: 

    Shorty.Tracking.Dialog.List:{};
    Shorty.Tracking.Dialog.Click:{};

The initializing sequence: 

    $(window).load(function(){
      //...
      var dfd = new $.Deferred();
      $.when(
        // load layout of dialog to show the list of tracked clicks
        Shorty.Tracking.init()
      ).done(function(){
        // bind actions to basic buttons
        Shorty.Tracking.Dialog.List.find('#close').on('click',function(){
          // ...
        });
        // ...
      });
      // ...
    })

The shortened init function: 

    init:function(){
        // ...
        var dfd=new $.Deferred();
        // two dialogs are used by this plugin
        var dialogs={
          'list':  Shorty.Tracking.Dialog.List,
          'click': Shorty.Tracking.Dialog.Click
        };
        // load dialogs from server
        $.each(['list','click'],function(i,dialog){
          if (...){
            // ...
            dfd.resolve();
          }else{
            // load dialog layout via ajax and create a freshly populated dialog
            $.ajax({
              type:     'GET',
              url:      OC.filePath('shorty-tracking','ajax','layout.php'),
              data:     { dialog: dialog},
              cache:    false,
              dataType: 'json'
            }).pipe(
              function(response){return Shorty.Ajax.eval(response)},
              function(response){return Shorty.Ajax.fail(response)}
            ).done(function(response){
              // create a fresh dialog
              // insert it alongside the existing dialogs in the top controls bar
              $('#controls').append(response.layout);
              switch (dialog){
                case 'list':
                  Shorty.Tracking.Dialog.List=$('#controls #shorty-tracking-list-dialog').first();
                  break;
                case 'click':
                  Shorty.Tracking.Dialog.Click=$('#controls #shorty-tracking-click-dialog').first();
              } // switch
              dfd.resolve();
            }).fail(dfd.reject)
          } // else
        }); // each
        return dfd.promise();
      },

