Skip to content

Instantly share code, notes, and snippets.

@relay-zz
Created September 8, 2012 06:29
Show Gist options
  • Save relay-zz/3672350 to your computer and use it in GitHub Desktop.
Save relay-zz/3672350 to your computer and use it in GitHub Desktop.
Deferred (Twisted API) implementation with no dependencies
/*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};
/* 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