There are two basic ways to use the semaphore: Initialize the semaphore with the number of asynchronous tasks you plan to use Call the v() function just before initializing an asynchronous task. At the end of each asynchronous task, call the p() function. The main difference between the two approaches is that the former isn't useful if you don't know how many asynchronous tasks you're going to launch, and the latter might fire the semaphore's callback multiple times, depending on how long your main "thread" takes and how long your asynchronous tasks take. An example of the former: var sem = new Semaphore(function() { log('All three async actions are complete'); }, 3); sendChat('', myFirstRoll, function(ops) { // Deal with the results of `myFirstRoll` sem.p(); }); sendChat('', mySecondRoll, function(ops) {
// Deal with the results of `mySecondRoll`
sem.p();
}); sendChat('', myThirdRoll, function(ops) {
// Deal with the results of `myThirdRoll`
sem.p();
}); You can't control the order in which the three sendChat calls will complete, but you're guaranteed that all of them are complete when the Semaphore callback runs. An example of the latter method: var sem = new Semaphore(function() { log('All running async actions have completed, but you might add some more and this will be called again'); }); _.each(myArray, function(item) { if (item.myProperty) { sem.v(); sendChat('', item.myProperty, function(ops) { // Deal with the results of `item.myProperty` sem.p(); }); } }); The linked implementation of Semaphore above also accepts a "context" object in the constructor; if you supply it, then using the keyword this in the semaphore callback will refer to the context object (otherwise, this will refer to the callback function itself). The linked implementation also allows your callback method to accept parameters. If you pass any extra parameters after context to the constructor, those parameters will be used as the defaults for the callback. If you supply any parameters to the p() function, those parameters will override the defaults given in the constructor. There's an example of that on the linked wiki page. (Note that if you're passing parameters to the callback through p() , only the parameters from the last p() will be used; you can use this to figure out which asyc operation finished last.)