About Deferred and Promises JQuery

2

I need help understanding this concept of Deferred and Promises in JQuery, it looks like there is a library for promises (is there really?) but JQuery is breaking the strand with implementation since version 1.5.

Help me understand applied in the example below:

 var
 log = function (msg) {
     $('#output').text($('#output').text() + ' ' + msg);
 },


 printDone = function (obj) {
     log(obj + ' done ..');
 },


 timer1 = $.Deferred(
     function (def) {
     setTimeout(function () {
         def.resolve("timer 1");
     }, 2000);
 }).promise(),


     timer2 = $.Deferred(function (def) {
         setTimeout(function () {
             def.resolve("timer 2");
         }, 4000);
     }).promise();
 timer1.done(function (data) {
     printDone(data)
 });
 timer2.done(function (data) {
     printDone(data)
 });
 $.when(timer1, timer2).done(function () {
     printDone('timer 1 and 2')
 })

Help me understand this, if possible comment on the code or explain how you feel better! I already gave a read, but I need a refresh so I understand better ..

    
asked by anonymous 21.03.2015 / 19:24

1 answer

6
timer1 = $.Deferred(...)

This creates a deferred ("deferred", "deferred"). This object starts in the "pending" state. Only when someone calls the method resolve or resolveWith it will pass to the "resolved" state. What does this mean?

  • If someone calls the method timer1.done(função) while their status is "pending", this function will be queued for later call;
  • When this object changes from "pending" to "resolved", all queued functions will be called, in order;
  • If someone calls the timer1.done(função) method while their status is "resolved", this function will be called immediately.

In this case, timer1 was [transformed into a promise and] used directly - with done - and indirectly, with when . Since it is still in the "pending" state, this means that both functions will be queued for later, and the done will be called before the when .

timer1 = $.Deferred(function (def) { ... }).promise();

This creates deferred and immediately calls a function that uses it in a single expression. Only that. This call above would be the equivalent of:

timer1 = $.Deferred();
(function(def) { ... }).call(timer1, timer1); // Tanto o this quanto o 1º argumento
                                              // são o próprio Deferred
timer1 = timer1.promise();

But the status of Deferred remains "pending," the extra function call does not necessarily change that. And indeed:

function (def) {
    setTimeout(function () {
        def.resolve("timer 1");
    }, 2000);
}

It can be seen that this function does nothing immediately - it triggers a new function to be executed in 2 seconds (via setTimeout ), and returns. The status of deferred remains the same.

2 seconds later ...

def.resolve("timer 1");

This changes the status of timer1 to "resolved". In the case, "timer 1" is just an argument, one could use something else, or things, or nothing. The argument (s) used in resolve goes straight to callbacks .

As stated, changing the status of a deferred from "pending" to "resolved" devel- ops the functions associated with it and executes them. The first one is the function:

timer1.done(function (data) {
    printDone(data)
});

Which - because it does not depend on anyone else - executes immediately. You should see "timer 1" being printed on output.

The second one was created using $.when , so it will only run when all its dependencies are resolved. timer1 is resolved, but timer2 is still pending, so this function still does not execute.

plus 2 seconds later ...

After another 2 seconds (4 total, according to the% w of% of the function used with setTimeout ), the following code is executed:

def.resolve("timer 2");

This resolves timer2 , de-parsing your callbacks and executing them, just as it did with timer2 . You should see timer1 printed on the output, since the code of "timer 2" was the first to be queued.

Now that both done and timer1 are in the "resolved" state, then the timer2 code is free to execute:

$.when(timer1, timer2).done(function () {
    printDone('timer 1 and 2')
})

You will then see when printed on the output. Note that this occurs before that "timer 1 and 2" returns - because it was this call that "fired" the callbacks still pending from def.resolve("timer 2") . This will be clear if you enter these two checks in the timers :

// Modifiquei o log pra ficar mais fácil a visualização
var log = function (msg) {
     $('#output').append('<li>' + msg + '</li>');
 },


 printDone = function (obj) {
     log(obj + ' done ..');
 },


 timer1 = $.Deferred(
     function (def) {
     setTimeout(function () {
         log("Vai resolver o timer 1");
         def.resolve("timer 1");
         log("Resolveu o timer 1");
     }, 2000);
 }).promise(),


     timer2 = $.Deferred(function (def) {
         setTimeout(function () {
             log("Vai resolver o timer 2");
             def.resolve("timer 2");
             log("Resolveu o timer 2");
         }, 4000);
     }).promise();
 timer1.done(function (data) {
     printDone(data)
 });
 timer2.done(function (data) {
     printDone(data)
 });
 $.when(timer1, timer2).done(function () {
     printDone('timer 1 and 2')
 })
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><ulid="output"></ul>
    
21.03.2015 / 20:11