dege
dege

Reputation: 2954

For iteration with async functions

I'm using a for each to process a list and i want that element n to be executed only when element n-1 is over:

var elements = ["stuff1", "stuff2", "stuff3"];

elements.forEach(function(element){
    someAsyncFunction(element, function(){
       console.log('do more stuff');
   });
});

I need that they wait for each other and execute in the right order.

EDIT : I bumped into process.nextTick(), but I'm not sure if it guarantees the waiting and order.

Upvotes: 3

Views: 114

Answers (2)

mb21
mb21

Reputation: 39189

A nice way is to make use of a promise library like Q or Bluebird and then implement a promiseWhile like this.

var Promise = require('bluebird');

var promiseWhile = function(condition, action) {
    var resolver = Promise.defer();

    var loop = function() {
        if (!condition()) return resolver.resolve();
        return Promise.cast(action())
            .then(loop)
            .catch(resolver.reject);
    };

    process.nextTick(loop);

    return resolver.promise;
};

Usage:

var sum = 0,
    stop = 10;

promiseWhile(function() {
    // Condition for stopping
    return sum < stop;
}, function() {
    // Action to run, should return a promise
    return new Promise(function(resolve, reject) {
        // Arbitrary 250ms async method to simulate async process
        // In real usage it could just be a normal async event that 
        // returns a Promise.
        setTimeout(function() {
            sum++;
            // Print out the sum thus far to show progress
            console.log(sum);
            resolve();
        }, 250);
    });
}).then(function() {
    // Notice we can chain it because it's a Promise, 
    // this will run after completion of the promiseWhile Promise!
    console.log("Done");
});

Upvotes: 2

Kijewski
Kijewski

Reputation: 26022

Just store the elements in an array exactly the same way as you did in your question. Then use elements.shift() to retrieve and remove the first element.

var elements = ["stuff1", "stuff2", "stuff3"];
(function next () {
    if (!elements.length) {
        return;
    }

    var element = elements.shift();
    someAsyncFunction(element, function (err, result) {
        …
        next();
    });
})();

Upvotes: 4

Related Questions