Created
September 8, 2012 06:29
-
-
Save relay-zz/3672350 to your computer and use it in GitHub Desktop.
Deferred (Twisted API) implementation with no dependencies
This file contains hidden or 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
/*Copyright(c)2012 relay.github.com http://opensource.org/licenses/MIT*/function Deferred(){this.callbacks=[]} Deferred.prototype={err:0,x:0,$:function(a){this.callbacks.push(a);2==this.x&&this._(this.o);return this},done:function(a){return this.$([a,0])},fail:function(a){return this.$([0,a])},always:function(a){return this.$([0,0,a])},then:function(a,c){return this.$([a,c])},reject:function(a){this.x||(this.err=1,this._(a));return this},resolve:function(a){this.x||this._(a);return this},_:function(a){this.x=1;for(var c=this.err,d=this.callbacks,b=d.shift(),e=a;b;)try{for(;b;){(b=b[2]||(c?b[1]:b[0]))&&(e= b(e||a));if(e instanceof Deferred){var f=this;e.always(function(b){f._(b||a);return b});return}b=d.shift()}}catch(g){c&&(b=d.shift()),this.err=c=1}this.o=e||a;this.x=2}};Deferred.when=function(a,c){if(!c)return a;for(var c=[].slice.call(arguments),a=new Deferred,d=c.length,b=d,e=[],f=function(c){return function(d){e[c]=d;--b||a.resolve(e)}},g=function(b){a.reject(b)};d--;)c[d].then(f(d),g);return a}; |
This file contains hidden or 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
/* Copyright (c) 2012 relay.github.com http://opensource.org/licenses/MIT | |
* | |
* Deferred is an implementation of the Promise pattern, which allows | |
* for asynchronous events to be handled in a unified way across an | |
* application. Deferred's are like callbacks on steroids. | |
* | |
* Rather than passing around callback functions, Deferred objects | |
* are passed around. Deferreds contain a queue of callback functions | |
* and manage the state of the asychronous event. | |
* | |
* When calling an asynchronous function, all functions should return a | |
* Deferred object. The caller function, having received the Deferred | |
* and having done whatever it wants to do, should also return that | |
* same Deferred when it exits, so that other parties have a chance to | |
* interact with it. | |
* | |
* The Deferred object represents the completed state of a future event. | |
* Interested parties can add a callback function to the Deferred that | |
* will be called when the Deferred event is deemed complete. | |
* | |
* When an asynchronous event is deemed completed, all the callbacks that | |
* were added to the Deferred will be called in serial order. The return | |
* value of each callback is passed as a parameter to the next callback. | |
* i.e., callback3(callback2(callback1( trigger(o) ))) | |
* | |
* After the event is deemed completed and all the callbacks are called, | |
* further callbacks which are added to the Deferred at a later stage | |
* will be executed immediately. | |
*/ | |
function Deferred() { | |
this.callbacks = [] | |
}; | |
Deferred.prototype = { | |
err: 0, | |
x: 0, | |
$: function(arr) { | |
this.callbacks.push(arr); | |
this.x == 2 && this._(this.o); | |
return this | |
}, | |
done: function(cb) { | |
return this.$([cb, 0]) | |
}, | |
fail: function(cb) { | |
return this.$([0, cb]) | |
}, | |
always: function(cb) { | |
return this.$([0, 0, cb]) | |
}, | |
then: function(cb, err) { | |
return this.$([cb, err]) | |
}, | |
reject: function(obj) { | |
this.x || (this.err = 1, this._(obj)); | |
return this | |
}, | |
resolve: function(obj) { | |
this.x || this._(obj); | |
return this | |
}, | |
_: function(obj) { | |
this.x = 1; | |
for(var state = this.err, cb = this.callbacks, method = cb.shift(), value = obj; method; ) { | |
try { | |
while(method) { | |
(method = method[2] || (state ? method[1] : method[0])) && (value = method(value || obj)); | |
if(value instanceof Deferred) { | |
var that = this; | |
value.always(function(v) {that._(v || obj); return v}); | |
return | |
} | |
method = cb.shift() | |
} | |
} catch(e) { | |
state && (method = cb.shift()), this.err = state = 1 | |
} | |
} | |
this.o = value || obj; | |
this.x = 2 | |
} | |
}; | |
Deferred.when = function(m, args) { | |
if(!args) return m; | |
args = [].slice.call(arguments); | |
m = new Deferred; | |
var i = args.length, | |
n = i, | |
res = [], | |
done = function(j) {return function(v) {res[j] = v; --n || m.resolve(res)}}, | |
fail = function(v) {m.reject(v)}; | |
while(i--) args[i].then(done(i), fail); | |
return m | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment