Javascript Question

Resolve promises one after another (i.e. in sequence)?

Consider the following code that reads an array of files in a serial/sequential manner.

returns a promise, which is resolved only once all files have been read in sequence.

var Q = require("q");

var readFile = function(file) {
... // Returns a promise.

var readFiles = function(files) {
var deferred = Q.defer();

var readSequential = function(index) {
if (index >= files.length) {
} else {
readFile(files[index]).then(function() {
readSequential(index + 1);

readSequential(0); // Start!

return deferred.promise;

The code above code works, but I don't like having to do recursion for things to occur sequentially. Is there a simpler way that this code can be re-written so that I don't have to use my weird

Originally I tried to use
, but that caused all of the
calls to happen concurrently, which is not what I want:

var readFiles = function(files) {
return Q.all( {
return readFile(file);

Answer Source

Update: In second thought - I might use a for loop instead:

var readFiles = function(files) {
  var p = Q();

      p = p.then(function(){ return readFile(file); }); // or .bind
  return p;

Or more compactly, with reduce:

var readFiles = function(files) {
  return files.reduce(function(p, file) {
             return p.then(function(){ return readFile(file); });
         },Q()); // initial

In other promise libraries (like when and Bluebird) you have utility methods for this.

For example, Bluebird would be:

var Promise = require("bluebird");
var fs = Promise.promisifyAll(require("fs"));

var readAll = Promise.resolve(files).map(fs.readFileAsync,{concurrency: 1 });
// if the order matters, you can use Promise.each instead and omit concurrency param

    // do stuff to read files.

In Q, what you have is about as good as you can get - you can shorten it with Array.prototype.reduce a bit and extract it into a generic method.

If you can use Q.async (that is you're on node) things get better:

Q.spawn(function* () {
    var results = [];
    for(var i = 0;i < files.length; i++){
        results.push(yield readFile(files[i]));

Just remember to run node with --harmony and remember it's experimental atm.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download