public
Last active

Deferred (Twisted API) implementation with no dependencies

  • Download Gist
deferred.js
JavaScript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
/* 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
};

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.