0

I am learning how to use jQuery's deferred, so I made a simple little example, so I could mess around.

function a() {
    var d = new $.Deferred,
        $A = $('#A'),
        $P = $('#P').progressbar();

    setTimeout(function() {
        $A.css('background-color', 'blue');
        d.notifyWith($P, [.5]);
    }, 2000);

    setTimeout(function() {
        $A.text('test');
        d.notifyWith($P, [1]);
        d.resolveWith($P, ['done']);
    }, 4000);

    return d.promise();
}
$('#G').click(function() {
    a().progress(function(x) {
        this.progressbar({
            value: x * 100
        });
    }).done(function(x) {
        alert(x)
    });
});​

DEMO: http://jsfiddle.net/NTICompass/3DDSa/3/

This example works great. After the operations complete, an alert pops up.

I read then you can combine multiple promises with $.when (which itself returns a promise), so I decided to break a() into 2 functions:

function a() {
    var d = new $.Deferred,
        $A = $('#A');

    setTimeout(function() {
        $A.css('background-color', 'blue');
        d.notify(.5);
    }, 2000);

    return d.promise();
}

function b() {
    var d = new $.Deferred,
        $A = $('#A');

    setTimeout(function() {
        $A.text('test');
        d.notify(1);
        d.resolve('done');
    }, 4000);

    return d.promise();
}

$('#G').click(function() {
    var $P = $('#P').progressbar();
    $.when(a(), b()).progress(function(x) {
        $P.progressbar({
            value: x * 100
        });
    }).done(function(x) {
        alert(x)
    });
});​

DEMO: http://jsfiddle.net/NTICompass/3DDSa/8/

I use $.when(a(), b()) to combine the 2 promises, but it's not working. The progress bar goes to 50%, but not to 100%, and my .done is never called.

It seems the the .notify (and the .resolve) inside b() aren't having any effect. What is wrong here? How do I use $.when to combine 2 promises?

gen_Eric
  • 223,194
  • 41
  • 299
  • 337
  • 2
    It doesn't look like you are ever resolving the `d` in the function `a`. The promise returned by `$.when` is resolved when all the promises it contains are resolved. See http://jsfiddle.net/3DDSa/6/ – Esailija Aug 10 '12 at 18:42
  • @Esailija: Adding `d.resolve()` to `a()` made the `.done` execute, but it displayed `undefined` in the alert (I am sending a value in the `d.resolve` inside `b()`), it also seems that the `.notify` inside `b()` isn't doing anything (the progrssbar is still at 50%). http://jsfiddle.net/NTICompass/3DDSa/9/ – gen_Eric Aug 10 '12 at 18:47
  • 1
    The arguments passed to `.done` in the `when`-promise are in the same order as when you created it. so `x` in `done` refers to the value that `a` was resolved with (`undefined` )and `arguments[1]` refers to the value that `b` was resolved with ( `"done"`). See http://jsfiddle.net/3DDSa/11/ – Esailija Aug 10 '12 at 18:51
  • @Esailija: Neat! I didn't realize `.done` got multiple parameters. Could that be the same for `.progress`? – gen_Eric Aug 10 '12 at 18:53
  • @Esailija: Seems `.progress` works the same way. Each time it's called, the arguments list grows. http://jsfiddle.net/NTICompass/3DDSa/13/ – gen_Eric Aug 10 '12 at 18:56
  • Looks like the progress is only being called for the first passed promise. I'm not really familiar with the progress thing. – Esailija Aug 10 '12 at 18:56
  • @Esailija: Seems `.progress` works the same way. Each time it's called, the arguments list grows. http://jsfiddle.net/NTICompass/3DDSa/13/ – gen_Eric Aug 10 '12 at 18:57
  • @Esailija: Well, you definitely solved the issue here, thanks dude. Wanna add that as an answer, so you can get some rep? :-P – gen_Eric Aug 10 '12 at 18:58

1 Answers1

3

It doesn't look like you are ever resolving the d in the function a. The promise returned by $.when is resolved when all the promises it contains are resolved. See http://jsfiddle.net/3DDSa/6

The arguments passed to .done in the when-promise are in the same order as when you created it. so x in done-callback refers to the value that a was resolved with (undefined) and arguments[1] refers to the value that b was resolved with ("done"). See http://jsfiddle.net/3DDSa/11

It looks like the progress callback to the when-promise works the same way, with increased arguments count.

Esailija
  • 138,174
  • 23
  • 272
  • 326
  • I'm still learning how deferred work, it's a little confusing X_X – gen_Eric Aug 10 '12 at 19:00
  • @Rocket it seems ok, just a small problem with `$.when` :) – Esailija Aug 10 '12 at 19:01
  • 1
    It should be noted that `.progress` also takes a function with two arguments. The progress bar will never push past 0.5 since that's always the value returned by a(). – Ian Bishop Aug 10 '12 at 19:09
  • @IanBishop doesn't seem that way http://jsfiddle.net/3DDSa/14/. It just gets whatever arguments you notify it with? – Esailija Aug 10 '12 at 19:12
  • 1
    @Esailija using `$.when` it does, same as `.done`. `.progress` is called twice, once with `x = 0.5` and the next with `x = 0.5`. If you have `.progress(x, y)` the first time you will have `x = 0.5, y = undefined` and the second time `x = 0.5, y = 1.0`. – Ian Bishop Aug 10 '12 at 19:17
  • A better solution to this is to instead add all of the progress notifications. For instance, `value: (x+y) * 100` with `a()` notifying .5 and `b()` notifying .5. – Ian Bishop Aug 10 '12 at 19:18
  • 1
    @IanBishop: Yep, that's what I'm doing. Though `x + undefined` is `NaN`, so you should do: `value: ((x||0) + (y||0)) * 100`. – gen_Eric Aug 10 '12 at 19:22