About Deferred and Promises Jquery

Asked

Viewed 1,130 times

3

I need help to understand this concept of Deferred and Promises in Jquery, it seems that there is a library for Promises(is there?) but Jquery is breaking the branch with the implementation of this 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 to understand this one, if possible comment the code or explain, as you think best! I already read it, but I need a refresh so I can understand it better..

1 answer

7


timer1 = $.Deferred(...)

This creates a deferred ("deferred", "deferred"). This object starts in the "pending" state. Only when someone call the method resolve or resolveWith he had passed to the "solved" state. What does that mean?

  • If someone calls the method timer1.done(função) while your state is "pending", this function will be queued to be called later;
  • When this object passes from the "pending" state to the "solved", all queued functions will be called, in order;
  • If someone calls the method timer1.done(função) while its state is "solved", this function will be called immediately.

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

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

This creates the deferred and immediately calls a function that uses it in a single expression. Just that. This above call 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 state of Deferred continues "pending", the call of the extra function does not change [necessarily] that. And indeed:

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

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

2 seconds later...

def.resolve("timer 1");

This changes the state of timer1 to "solved". In case, "timer 1" is only an argument, one could use something else, or things, or nothing. The (s) arguments(s) used(s) in the resolve passes(m) directly to callbacks.

As has been said, change the state of a deferred from "pending" to "solved" unhook the functions associated with it and executes them. The first of these is the function:

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

Which - as it does not depend on anyone else - runs immediately. You should see a "timer 1" being printed on exit.

The second was created through $.when, so that it will only be executed when all your dependencies are solved. timer1 is resolved, but timer2 is still pending, so that function does not yet perform.

2 more seconds later...

After 2 more seconds (4 in total as per setTimeout of the function used with timer2), the following code is executed:

def.resolve("timer 2");

That solves the timer2, unofficial callbacks and executing them, as happened with the timer1. You should see "timer 2" printed on exit, since the code of the done was the first to be lined up.

Now that so much timer1 how much timer2 are in the "solved" state, so the code of the when is free to run:

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

You’ll see then "timer 1 and 2" printed on output. Note that this occurs before that the def.resolve("timer 2") return - because it was this call that "fired" the callbacks still pending of timer2. This will be clear if you insert these two checks into the creation of 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>
<ul id="output"></ul>

  • if I had a function called Callajax, and in it I had an AJAX request, I could do : $.when(CallAjax).done(function(){}); for me to perform some function after the request, considering that asynchronous operations (fade,ajax) already have precedents?

  • 1

    @Alexandrec.Caus Yes, even this is the most recommended way to do this in new codes (I just don’t know if the when it’s necessary, I think you can just do CallAjax.done(fn)). There are also some functions that nay return a file directly, but allow you to request one, ex.: $(elemento).hide(2000).promise() (returns a common jQuery object, but when asking the Password it gives you one that will only solve at the end of the hide animation)

  • Perfect @mgibsonbr, it’s getting clearer and clearer, I’m getting beaten to learn this because I’m confusing deferred with Promise, and there’s still deferred.promise(), but to solve me slowly, I hope to be 100% interacted of this, worth so far, a great hug for you beast!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.