Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

chaining promises with q.js

I'm trying to understand how promise chaining works. I'm using q.js. Here's what I'm playing with.

var Q = require("q"); // npm install q

// the function Q(value) returns a fulfilled promise with the value... I think.
Q(1).then(Q(2)).then(Q(3)).then(Q(4)).then(function(n) {
    console.log(n);
});

Q(1).then(function(n) {
    return Q(2);
}).then(function(n) {
    return Q(3);
}).then(function(n) {
    return Q(4);
}).then(function(n) {
    console.log("done: " + n);
});

My question basically boils down to why does the first one log 1 while the latter one logs what I would expect and basically logs 1 through 4. I had hoped the first one would log 4 instead of 1.

I really just wanted to be able to have some methods that return promises and then chain them together in a waterfall like fashion - I guess I could use async and waterfall, but just wanted to know if this could be achieved w/ promises.

like image 458
Anon Avatar asked Nov 19 '13 14:11

Anon


1 Answers

It's because then doesn't expect another promise as an argument. Rather it expects handler functions, an callback and/or an errback, the former you are passing in your 2nd example. Indeed any argument that is not a function is simply ignored.

From the docs:

If you return a value in a handler, outputPromise will get fulfilled.

If you throw an exception in a handler, outputPromise will get rejected.

If you return a promise in a handler, outputPromise will “become” that promise. Being able to become a new promise is useful for managing delays, combining results, or recovering from errors.

So yes, chaining promises can be done. You're doing it right in your 2nd example.

It's possible that the contrived example here of passing fulfilled promises makes the way chaining promises works seem overly verbose, but in real world usage, you typically chain promises because you're interested in their return values, e.g.:

somethingAsync().then(function (n) {
  return somethingElseAsync(n);
})
.then(function (n) {
  return somethingElseAsync(n);
})
.then(function (result) {
  // ...
})

(Actually this mirrors async.waterfall. If you just wanted to call a series of async functions in order with no regards to their results you could use async.series)

like image 139
numbers1311407 Avatar answered Oct 30 '22 19:10

numbers1311407