14

I need to execute a bunch of asynchronous methods (client SQLite database), and call only one final callback.

Of course, the ugly way is:

execAll : function(callBack) {
        asynch1(function() {
            asynch2(function() {
                ...
                asynchN(function() {
                    callBack();
                })
            })
        });
    }

But I know there are better ways to do it. Intuitively I would detect when all call back has been called with a counter to call the final callback.

I think this is a common design-pattern, so if someone could point me in the right direction...

Thanks in advance !

4 Answers 4

21

this is easy

var callback = (function(){
    var finishedCalls = 0;
    return function(){
        if (++finishedCalls == 4){
             //execute your action here
        }
    };
})();

Just pass this callback to all your methods, and once it has been called 4 times it will execute.

If you want to use factory for this then you can do the following

function createCallback(limit, fn){
    var finishedCalls = 0;
    return function(){
        if (++finishedCalls == limit){
             fn();
        }
    };
}


var callback = createCallback(4, function(){
    alert("woot!");
});


async1(callback);
async2(callback);
async3(callback);
async4(callback);
Sign up to request clarification or add additional context in comments.

5 Comments

And if any such pattern exist, then this is it.
Thanks a lot Sean, it was easy, and implement something like your first solution before seeing your answer. But I like more your callback factory, it is very elegant, i will use it ;-)
And if it is a pattern, it has to have a name. Suggestions?!
Here is utilliy function same as this answer gist.github.com/4350633 read more here markandey.com/2012/12/how-to-get-output-of-multiple.html
If your application already use underscorejs, then you can call _.after(). Its working is exactly like factory given in this answer.
8

I've written some async utilities you might find useful, allowing you to write your example as:

function(callback) {
    async.series([
        asynch1(),
        asynch2(),
        ...
        asynchN()
    ], callback);
}

Or, if you wanted to run them in parallel, as:

function(callback) {
    async.parallel([
        asynch1(),
        asynch2(),
        ...
        asynchN()
    ], callback);
}

There are loads of other useful functions like async map/reduce too:

http://caolanmcmahon.com/async.html

Hope that helps!

Comments

2

You should consider using Deferred pattern for asynchronous methods. You can get more information from the this StackOverflow question and answers:

What are the differences between Deferred, Promise and Future in JavaScript?

The marked answer from jnewman was good actually!

Hope this helps.

Comments

0

Promises can help manage this. There are two general scenarios - parallel and serial. Parallel can be accomplished using Promise.all(), serial is more complex - task B can only start when task A is done. Here's a bare-bones sample:

// returns a promise that resolves as the task is done
const wrap = (fn, delay) => new Promise(resolve => setTimeout(_ => resolve(fn()), delay));
const task = (fn, delay) => delay ? wrap(fn, delay) : Promise.resolve(fn());

// given a list of promises, execute them one by one.
const sequence = async l => l.reduce(async (a, b) => [].concat(await a, await b));

const tasks = [
    task(_ => console.log("hello world")),
    task(_ => console.log("hello future"), 1000)
];

sequence(tasks).then(_ => console.log("all done"));

You may need some ES6/7 translation to make this work in browsers or older node versions.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.