2

I'm assuming Q.all([p1, p2, p3]).then(f) is no different than

p1.then(function () {
    p2.then(function () {
        p3.then(f);
    });
});

Because when p1, p2 and p3 are created the async calls have already been made and we just have to wait for all of them to resolve and the order doesn't matter.

Am I correct?

If so, I've been looking at kriskowal's all implementation. I thought it would be something similar (chaining promises using then). But I find it to be implemented completely differently? Why is that?

Edit:

Let me be a little more clear. Say p1, p2, p3 resolve in 100ms, 200ms, 300ms respectively. The order of waiting for their response makes no differens

p1.then(function () {
    // we're here at 100ms
    p2.then(function () {
        // 100ms later we're here
        p3.then(f); // f gets called 100ms later (at 300ms)
    });
});

p3.then(function () {
    // we're here at 300ms
    p2.then(function () {
        // boom! resolves in a snap
        p1.then(f); // f also gets called instantly (at 300ms)
    });
});

In both examples we only wait 300ms for all three promises to resolve.

Ali Dorosty
  • 149
  • 2
  • 10

2 Answers2

4

I'm assuming Q.all([p1, p2, p3]).then(f) is no different than

p1.then(function () {
    p2.then(function () {
        p3.then(f);
    });
});

Not exactly. f is getting passed an array of results, and you always want to return (promises for) results; so you'd write

p1.then(function(r1) {
    return p2.then(function(r1) {
        return p3.then(function(r3) {
            return f([r1, r2, r3]);
        });
    });
});

// or equivalently, better matching a separate `Q.all`:
p1.then(function(r1) {
    return p2.then(function(r1) {
        return p3.then(function(r3) {
            return [r1, r2, r3];
        });
    });
}).then(f);

Because when p1, p2 and p3 are created the async calls have already been made and we just have to wait for all of them to resolve and the order doesn't matter.

Am I correct?

A bit. Indeed, a naive version of .all could be implemented like this.

However, we need to look at an important "edge" case: When the promises don't get fulfilled but are rejected. Suddenly, the nested structure of the callbacks becomes wrong - as we want to watch all of the three promises in parallel and from the beginning. Let's say p3 resolves after 200ms, p1 after 300ms, and p2 is rejected after 100ms.

With your nested then callbacks, it would wait the entire 300ms (p1) before p2 is observed the first time - however, it has long been rejected already. Instead, the .all method wants to fail early, and reject the result promise as soon as any of the passed promises is rejected.

Therefore (and a bit for performance), Q.all is internally using the deferred pattern.

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
0

Nope. They are different.

Here, you assume p2 will only start after p1 is done. And p3 only after p2 is done.

p1.then(function () {
    p2.then(function () {
        p3.then(f);
    });
});

So basically, you introduced sequence and dependency. Do 1, then 2, then 3. This is ideal if p3 depends on the result of p2 and p2 depends on the result of p1. However, this introduces a lot of complexity and dependency to your code, so you better use it carefully. Or even avoid it as much as you can.

The following, however, doesn't require sequence:

Q.all([p1, p2, p3]).then(f)

f depends on all 3 being finished (p1, p2 and p3), but there's no cross-dependency between the three. p2 might finish first, then p1, or p3 (they are async afterall). No order is required. The only requirement is that all three are finished in whichever order for f to get triggered. In general, this is much better when possible. p2 and p3 don't have to wait until p1 is done to start making requests or processing anything.

Hope I answered your question :)

Arthur Camara
  • 328
  • 1
  • 4
  • 1
    Thank you for your answer but I think your wrong. I think when we have p1 and p2 and p3 that means all three requests have been sent and we're just waiting for their response. It doesn't matter in which order we "wait". It's not like we send p1, wait for the response and then send p2. – Ali Dorosty Nov 08 '14 at 11:44
  • @Arthur: Note that `p1`, `p2`, `p3` are promises, not the calls that create promises. – Bergi Nov 08 '14 at 13:25
  • True! Your explanation was great :) – Arthur Camara Nov 08 '14 at 19:10