Created
December 1, 2009 15:54
-
-
Save fictorial/246384 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* A PromiseGroup accepts a number of named promises, waits for each to | |
* complete (succeed, fail, timeout, cancel), then emits an event to signify | |
* that all accepted promises have completed. | |
* | |
* Names of promises are arbitrary but must be strings and must be unique | |
* across the set of all named promises a PromiseGroup accepts. | |
* | |
* When an individual promise completes, a PromiseGroup emits "one_done" | |
* passing the name of the promise, the outcome ('ok', 'fail', 'cancel', or | |
* 'timeout') and the promise's result. For 'ok' the result is an array of | |
* arguments from the promise's emitSuccess. For 'error' its just the error. | |
* | |
* When all promises have completed, the PromiseGroup emits an event "all_done" | |
* passing an object that describes the outcome of each named promise. The | |
* object takes the form: | |
* | |
* { ok: { 'name': result, ... }, | |
* fail: { 'name': error, ... }, | |
* timeout: { 'name': null, ... }, | |
* cancel: { 'name': result, ... } } | |
* | |
* where 'name' is the name of a promise, 'result' is an array, | |
* 'error' is a string. | |
* | |
* There is no implied dependency between promises. | |
* | |
* There's no (public) way to know if a Promise has fired so be sure | |
* to not have a PromiseGroup accept Promises that have already fired | |
* as you will wait for the PromiseGroup forever. | |
*/ | |
function PromiseGroup() { | |
this.promises = {ok:{}, fail:{}, cancel:{}, timeout:{}, waiting:{}}; | |
} | |
exports.PromiseGroup = PromiseGroup; | |
require('sys').inherits(PromiseGroup, process.EventEmitter); | |
PromiseGroup.prototype.add = function (promise, name) { | |
if (!promise || !(promise instanceof process.Promise)) | |
throw new Error("Promise required"); | |
if (!name || typeof(name) != "string" || name.length === 0) | |
throw new Error("Promise name required"); | |
var self = this; | |
self.promises.waiting[name] = 1; | |
function one_done(name, outcome, result) { | |
self.promises[outcome][name] = result; | |
delete self.promises.waiting[name]; | |
self.emit("one_done", name, outcome, result); | |
var has_more_coming = false; | |
for (var x in self.promises.waiting) { | |
has_more_coming = true; | |
break; | |
} | |
if (!has_more_coming) { | |
delete self.promises.waiting; | |
self.emit("all_done", self.promises); | |
} | |
}; | |
promise.addCallback(function () { | |
one_done(name, 'ok', Array.prototype.slice.call(arguments)); | |
}).addErrback(function (e) { | |
var outcome = 'fail', result = e; | |
if (e instanceof Error && e.message === "timeout") { | |
outcome = 'timeout'; | |
result = null; | |
} | |
one_done(name, outcome, result); | |
}).addCancelback(function () { | |
one_done(name, 'cancel', Array.prototype.slice.call(arguments)); | |
}) | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment