When programming Javascript it is sometimes neccessary to start multiple methods, let them run all at the same time and then have a single callback that is called when all of the methods are finished. Dealing with raw Javascript, it is convenient to use a simple object to do the magic for you and just supply methods to add, that is what the class below does:
function AsyncBin(callback) {
if (callback===undefined) callback = function() {};
this._async = {};
this._id = 0;
this._callback = callback;
this._done = false;
}
AsyncBin.prototype.isWaiting = function() {
for (var key in this._async) {
if (this._async.hasOwnProperty(key) && this._async[key]) {
return true;
}
}
return false;
};
AsyncBin.prototype.reset = function() {
this._done = false;
//mark all of the callback methods as not been completed
for (var key in this._async) {
if (this._async.hasOwnProperty(key)) {
this._async[key] = true;
}
}
};
AsyncBin.prototype.ready = function(callback) {
if (callback!==undefined) {
this._callback = callback;
}
//run the test once if it has not already been called
this._done = true;
if (!this.isWaiting()) {
this._callback();
}
};
AsyncBin.prototype.callback = function(callbackId) {
if (callbackId===undefined) {
callbackId = this.add();
}
var self = this;
return function() {
if (self._async.hasOwnProperty(callbackId) && self._async[callbackId]) {
self._async[callbackId] = false;
if (self._done && !self.isWaiting()) {
self._callback();
}
}
};
};
AsyncBin.prototype.remove = function(callbackId) {
delete this._async[callbackId];
};
AsyncBin.prototype.add = function() {
var callbackId = String(this._id++);
this._async[callbackId] = true;
return callbackId;
};
Usage
You can use the class below as follows:
var startTime = new Date().getTime();
var bin = new AsyncBin(done);
longTask(bin.callback());
longTask2(bin.callback());
bin.ready();
function done() { alert("Took " + (new Date().getTime() - startTime) + " ms"); };
function longTask(callback) { setTimeout(callback, 1000); };
function longTask2(callback) { setTimeout(callback, 2000); };
You can also create callback ids in advance and manually remove them from the bin if you wish:
var bin = new AsyncBin(function() {
alert("done");
});
var done1 = bin.add();
longTask(bin.callback(done1));
bin.ready();
setTimeout(function() {
done1.cancel(); //remove the callback method from the bin
bin.ready(); //force the bin to execute its done method if the other items are also ready
}, 1000);
Make a comment
Contribute to this article and have your say.