Marcio Marcio - 5 months ago 16
Node.js Question

How to proper chain promises calls that depend on one another?

I have the following code:

const request = require('request-promise');

request(validateEmailOptions).then(function(result) {
if (result.valid) {
request(createUserOptions).then(function (response) {
if (response.updatePassword) {
request(modifyUserOptions).then(function (response) {
return res.redirect('/signin');
}).catch(function(error) {
return res.redirect('/error');
});
}
}).catch(function(error) {
return res.redirect('/error');
});
} else {
return res.redirect('/error');
}
})
.catch(function (reason) {
return res.redirect('/error');
});


Basically, it's a chain of request call, each one based on the result of the previous call. The problem is that I have many more lines in each condition and as a result, my code is bloated and hard to read and follow. I want to know if there is a better way to write the call chain using request-promises or simply request and bluebird.

Answer

You can unnest the promises. Think that this:

f(a).then(function(a) {
  return g(b).then(function(b) {
    return h(c)
  })
})

Is the same as:

f(a).then(function(a) {
  return g(b)
}).then(function(b) {
  return h(c)
})

I would recommend failing as early as possible, that means handling the error condition first, and having meaningful error messages to be able to log them if need be. Finally, you can propagate the error and handle it in a single catch. To put it in context in your code:

request(validateEmailOptions).then(function(result) {
  if (!result.valid) {
    throw new Error('Result is not valid');
  }
  return request(createUserOptions);
}).then(function(response) {
  if (!response.updatePassword) {
    throw new Error('Password is not updated');
  }
  return request(modifyUserOptions);
}).then(function(response) {
  return res.redirect('/signin');
}).catch(function(error) {
  // you may want to log the error here
  return res.redirect('/error');
});
Comments