Joins any number of asynchronous calls together -
similar to how pthread_join works for C threads
and when() works for Q-style promises.
It's basically a callback counter that lets you know when everything is done.
Installation
Node.JS (Server):
Browser:
You can install from bower:
Or download the raw file from https://raw.github.com/FuturesJS/join/master/join.js:
wget https://raw.github.com/FuturesJS/join/master/join.js
Browser Usage
<script src="join.js"></script>
;(function () { 'use strict'; var join = window.Join.create() ; // Use `join.add()` in place of a callback function setTimeout(join.add(), 500, 'I', 'really'); setTimeout(join.add(), 700, 'really', 'LOVE'); setTimeout(join.add(), 200, 'JavaScript'); // Use `join.notify()` for incremental updates join.notify(function (i, args) { console.log( 'Callback #' + (i + 1) + ' of ' + join.length + ' completed', args ); }); // Use `join.then(cb)` to fire `cb` when all of the `join.add()` callbacks have been called. join.then(function (i, love, js) { console.log('All of the timeouts have completed'); console.log(i, love, js); }); }());
Node.js Usage
'use strict'; var request = require('request') , Join = require('join').Join , join = Join.create() ; // Use `join.add()` in place of a callback function request.get('https://www.google.com', join.add()); request.get('http://www.yahoo.com', join.add()); request.get('https://www.bing.com', join.add()); // Use `join.notify()` for incremental updates join.notify(function (i, args) { console.log( 'Callback #' + (i + 1) + ' of ' + join.length + ' completed', args ); }); // Use `join.then(cb)` to fire `cb` when all of the `join.add()` callbacks have been called. join.then(function (googleArgs, yahooArgs, bingArgs) { console.log('All of the requests have completed'); console.log(googleArgs[2]); console.log(yahooArgs[2]); console.log(bingArgs[2]); });
API
Join
join = Join.create(defaultContext=null)- create a Join that will count callbacksjoin.add()- creates a joinable callback that you can throw aroundjoin.notify(progressCallback, context=null)join.then(finalCallback, context=null)- Fires
finalCallbackwhen all joined callbacks have completed - Must be called after the last
add()
- Fires
join.length- the number of timesjoin.add()has been called
Potential Gotchas
Order matters
The arguments to join.then(cb) are in the order that the join.add() were called.
callbackA = join.add(); callbackB = join.add(); doAsyncStuff(callbackB); doAsyncStuff(callbackA); join.then(function (callbackAArgs, callbackBArgs) { console.log(callbackAArgs, callbackBArgs); });
Callback within a callback
If you handle the join callback inside of another callback then you'll need to place the join callback in the parent scope.
Fails:
request.get('http://www.yahoo.com', join.add()); setTimeout(function () { request.get('https://www.bing.com', join.add()); }, 100); join.then(function () { console.log('all completed'); });
Works as expected:
request.get('http://www.yahoo.com', join.add()); bingCallback = join.add() setTimeout(function () { request.get('https://www.bing.com', bingCallback); }, 100);
Losing thisness
Fails:
// `doStuff` loses the `this` binding to `myObject` join.then(myObject.doStuff);
Works as expected:
// `doStuff` retains the `this` binding
join.then(myObject.doStuff, myObject);
Also works as expected:
// `doStuff` retains the `this` binding
join.then(function (argsA, argsB, argsC) {
myObject.doStuff(argsA, argsB, argsC);
});