Juergen
Juergen

Reputation: 871

node.js Q promise then chaining of promises

the documentation says that chaining of promises works like

return getUsername()
  .then(function (username) {
     return getUser(username);
  })
  .then(function (user) {

wouldn't it be nice if the following would work as well?

return getUsername()
  .then(getUser)
  .then(function (user) {

I stumbled upon it because this is what I intuitively did and it didn't work.

thanks a lot

Upvotes: 1

Views: 647

Answers (1)

Benjamin Gruenbaum
Benjamin Gruenbaum

Reputation: 276596

Yes, it works.

There are two reasons it might fail: variable vs function hoisting or dynamic this.

Hoisting and variable definitions.

A difference between:

var foo = bar;

And:

var foo = function(x){ return bar(x); }

Given it's bar's signature is that in the second snippet bar is lazily evaluated. So if bar is undefined you'll get an error in the first example but not the second. Most promise libraries ignore (and have to because of the specification) undefined passed to then and simply return the same promise.

This issue in your example might look like:

return getUsername()
  .then(function (username) {
     return getUser(username); // note it's a method
  })
  .then(function (user) { ...

// later on in the file after the function ended
var getUser = function(){
    // because of the function wrap above, this will work since 
    // the function(){ causes it to be lazily evaluated
};

On the other hand doing:

return getUsername()
  .then(getUser)
  .then(function (user) {

// later on in the file outside the function
var getUser = function(username){
       // code here
};

Is the same as doing:

return getUsername()
  .then(undefined) // remember, promises ignore this
  .then(function (user) {

This has to do with how JavaScript handles hoisting of variables vs. hosting of function declarations.

Dynamic this

The reason it's not working is that your code actually looks a bit different. Your code is more like:

return getUsername()
  .then(function (username) {
     return someObj.getUser(username); // note it's a method
  })
  .then(function (user) {

And in fact getUser is accessing this inside it - this makes this an unbound function which depends on this. Remember that JavaScript has dynamic this so you can't simply do:

return getUsername()
  .then(someObj.getUser) // this won't work, pun intended
  .then(function (user) {

Now, in order to make it work - you can bind it for example:

return getUsername()
  .then(someObj.getUser.bind(someObj) // IE9+
  .then(function (user) {

// if using bluebird, this is faster:
return getUsername().bind(someObj)
  .then(someObj.getUser) 
  .then(function (user) {

Or use the longer version with the function expression.

This might not be your specific issue - but 9 out of 10 times someone asks this - it solves their problem.

Upvotes: 1

Related Questions