Skip to content

Instantly share code, notes, and snippets.

@blixt
Created October 10, 2012 22:33
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save blixt/3868945 to your computer and use it in GitHub Desktop.
Save blixt/3868945 to your computer and use it in GitHub Desktop.
Waiters (promises/deferreds/futures)
function Waiter(context) {
if (context) { this.context = context; }
}
Waiter.prototype.failed = function (cb) {
if (this.result) {
if (!this.success) { cb.apply(this.context || this, this.result); }
} else {
if (!this.failedCbs) { this.failedCbs = []; }
this.failedCbs.push(cb);
}
return this;
};
Waiter.prototype.then = function (cb) {
if (this.result) {
if (this.success) { cb.apply(this.context || this, this.result); }
} else {
if (!this.thenCbs) { this.thenCbs = []; }
this.thenCbs.push(cb);
}
return this;
};
Waiter.prototype.fail = function () {
if (this.result) { return; }
this.result = arguments;
this.success = false;
var cbs = this.failedCbs;
delete this.failedCbs;
delete this.thenCbs;
if (!cbs) { return; }
var i, len = cbs.length;
for (i = 0; i < len; i++) {
cbs[i].apply(this.context || this, arguments);
}
};
Waiter.prototype.failAfter = function (ms) {
var waiter = this;
setTimeout(function () {
waiter.fail();
}, ms);
};
Waiter.prototype.finish = function () {
if (this.result) { return; }
this.result = arguments;
this.success = true;
var cbs = this.thenCbs;
delete this.failedCbs;
delete this.thenCbs;
if (!cbs) { return; }
var i, len = cbs.length;
for (i = 0; i < len; i++) {
cbs[i].apply(this.context || this, arguments);
}
};
Waiter.join = function (list) {
var waiters = [].slice.call(list instanceof Array ? list : arguments);
var count = waiters.length;
var w = new Waiter();
w.waiters = waiters;
if (!count) {
w.finish();
return w;
}
w.remaining = count;
var then = Waiter.joinThen.bind(w), failed = Waiter.joinFailed.bind(w);
var i;
for (i = 0; i < count; i++) {
waiters[i].then(then).failed(failed);
}
return w;
};
Waiter.joinThen = function () {
if (!this.remaining || --this.remaining) { return; }
delete this.remaining;
var result = [], i, len = this.waiters.length;
for (i = 0; i < len; i++) {
result.push.apply(result, this.waiters[i].result);
}
this.finish.apply(this, result);
};
Waiter.joinFailed = function () {
if (!this.remaining) { return; }
delete this.remaining;
this.fail.apply(this, arguments);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment