How to chain a variable number of promises in Q, in order? How to chain a variable number of promises in Q, in order? node.js node.js

How to chain a variable number of promises in Q, in order?


There's a nice clean way to to this with [].reduce.

var chain = itemsToProcess.reduce(function (previous, item) {    return previous.then(function (previousValue) {        // do what you want with previous value        // return your async operation        return Q.delay(100);    })}, Q.resolve(/* set the first "previousValue" here */));chain.then(function (lastResult) {    // ...});

reduce iterates through the array, passing in the returned value of the previous iteration. In this case you're returning promises, and so each time you are chaining a then. You provide an initial promise (as you did with q.resolve("start")) to kick things off.

At first it can take a while to wrap your head around what's going on here but if you take a moment to work through it then it's an easy pattern to use anywhere, without having to set up any machinery.


I like this way better:

var q = require('q'),    itemsToProcess =  ["one", "two", "three", "four", "five"];function getDeferredResult(a) {  return (function (items) {    var deferred;    // end    if (items.length === 0) {      return q.resolve(true);    }    deferred = q.defer();    // any async function (setTimeout for now will do, $.ajax() later)    setTimeout(function () {      var a = items[0];      console.log(a);      // pop one item off the array of workitems      deferred.resolve(items.splice(1));    }, 600);    return deferred.promise.then(getDeferredResult);  }(a));}q.resolve(itemsToProcess)  .then(getDeferredResult);

The key here is to call .then() on the deferred.promise with a spliced version of the array of workitems. This then gets run after the initial deferred promise resolves, which is in the fn for the setTimeout. In a more realistic scenario, the deferred promise would get resolved in the http client callback.

The initial q.resolve(itemsToProcess) kicks things off by passing in the work items to the first call of the work fn.

I added this in hopes it would help others.


Here is a concept of a state machine defined with Q.

Suppose you have the HTTP function defined, so it returns a Q promise object:

var Q_http = function (url, options) {  return Q.when($.ajax(url, options));}

You can define a recursive function nextState as following:

var states = [...]; // an array of states in the system.// this is a state machine to control what url to get data from// at the current state function nextState(current) {  if (is_terminal_state(current))    return Q(true);  return Q_http(current.url, current.data).then(function (result) {    var next = process(current, result);    return nextState(next);  });}

Where function process(current, result) is a function to find out what the next step would be according to the current state and the result from the HTTP call.

When you use it, use it like:

nextState(initial).then(function () {  // all requests are successful.}, function (reason) {  // for some unexpected reason the request sequence fails in the middle.});