0

Here i try to load several JS files sequentially. Problem is $.when does not wait for the chain to complete. But the last $.Deferred.then works as expected. What should i do to make $.when work?

var urls = [
    "https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.js",
    "https://cdnjs.cloudflare.com/ajax/libs/photoswipe/4.1.2/photoswipe.js",
    "https://cdnjs.cloudflare.com/ajax/libs/photoswipe/4.1.2/photoswipe-ui-default.js"
];
var xxx = $.Deferred();
xxx.then(function() {
        options = {
            dataType: "script",
            url: urls[0],
            cache: false
        };
        return $.ajax(options).promise();
    })
    .then(function() {
        options = {
            dataType: "script",
            url: urls[1],
            cache: false
        };
        return $.ajax(options).promise();
    })
    .then(function() {
        options = {
            dataType: "script",
            url: urls[2],
            cache: false
        };
        return $.ajax(options).promise();
    }).then(function() {
        $("body").append("This is correct. All files are loaded.<br>");
    });

$.when(xxx).done(function() {
    $("body").append("This is wrong. JS files are not loaded yet.<br>");
});
xxx.resolve();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

Fiddle https://jsfiddle.net/ergec/fmrj6qgp/

Ergec
  • 11,608
  • 7
  • 52
  • 62
  • If it is working with `$.Deferred.then` as expected then why you want to use `$.when` ? – Yogesh Patel Oct 27 '17 at 10:29
  • There is no reason to use `$.when()` here at all or your `$.Deferred()`. Start the chain with `$.ajax(...).then()`. Your last `.then()` handler should work just fine to know when the whole chain is done. There's also no reason to use `return $.ajax().promise()` when return `$.ajax(...)` works just fine. – jfriend00 Oct 27 '17 at 15:09

1 Answers1

1

Your method does not work because you create two branches off the same promise. You have the equivalent of:

var xxx = $.Deferred();
xxx.then(...).then(...);     // promise chain 1
xxx.then(...)                // promise chain 2
xxx.resolve();               // start the race between the two promise chains

That is simply a race between two separate promise chains that are not sequenced or coordinated. Whichever one takes less time to execute will get to its end first. There is zero coordination between them.

See Chaining vs. Branching and p.then().then() vs. p.then(); p.then() for further explanation.

And, your use of $.when(xxx).done() is unnecessary and not really part of the issue at all. You would get the same result with xxx.done().


You can fix it by only using one promise chain:

p.then(...).then(...).then(...)

Then, everything is properly sequenced and coordinated.

var urls = [
    "https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.js",
    "https://cdnjs.cloudflare.com/ajax/libs/photoswipe/4.1.2/photoswipe.js",
    "https://cdnjs.cloudflare.com/ajax/libs/photoswipe/4.1.2/photoswipe-ui-default.js"
];
let options = {
  dataType: "script",
  url: urls[0],
  cache: false
};
$.ajax(options).then(function() {
    let options = {
      dataType: "script",
      url: urls[1],
      cache: false
    };
    return $.ajax(options);
}).then(function() {
    let options = {
      dataType: "script",
      url: urls[2],
      cache: false
    };
    return $.ajax(options).then(function() {
          $("body").append("Last script loaded<br>");
    });
}).then(function() {
      $("body").append("This is correct. All files are loaded.<br>");
});

Working example: https://jsfiddle.net/jfriend00/tLp68a3q/


Or, if you still wanted to initialize your chain with var xxx = $.Deferred() so you could start it later with xxx.resolve(), then you can do that too, but you can't use xxx.then() or $.when(xxx) because that is a completely separate branch that is not linked to the other promise chain at all.

Working example starting with $.Deferred(): https://jsfiddle.net/jfriend00/y5n3hb99/

jfriend00
  • 683,504
  • 96
  • 985
  • 979