-
Notifications
You must be signed in to change notification settings - Fork 110
Open
Labels
Description
For learning promises, I made my own little implementation, see code below. I'm a Javascript newbie, so Douglas, don't be too hard on me please ;-)
For simplicity, it uses process.nextTick
, so it only works in nodejs for now.
However, all 872 specs of your test suite pass, whether or not I 'adopt the state' of a 'thenable' passed as an argument to the reject
method. See the single comment in the code.
What is the correct behavior?
Thanks a lot,
Peter Verswyvelen
var deferred = (function() {
function Deferred() {
this.promise = {
then: this.then.bind(this),
};
this.thens = [];
}
function call_thens(state, value, thens) {
thens.forEach(function (then) {
var cfn = then[state],
next_value = value,
next_state = state;
if (typeof cfn === "function") {
try {
next_value = cfn(value);
next_state = "done";
} catch (error) {
next_value = error;
next_state = "fail";
}
}
then.next.transit(next_state, next_value);
});
}
function then_transit(id, state, value) {
if (this.state === id) {
delete this.state;
this.transit(state, value);
}
}
var next_then_id = 0;
Deferred.prototype = {
asap: function () {
process.nextTick(call_thens.bind(
this, this.state, this.value, this.thens));
this.thens = [];
},
switchTo: function(state, value) {
this.value = value;
this.state = state;
this.asap();
},
transit: function (state, value) {
if (typeof this.state === "undefined") {
// All tests succeeds with or without the state === "done" check?
if (state === "done" &&
(typeof value === "function" ||
(typeof value === "object" && value !== null))) {
try {
if (value === this.promise)
throw new TypeError();
var then = value.then;
if (typeof then === "function") {
this.promise.then = then.bind(value);
var id = this.state = ++next_then_id;
try {
then.call(value,
then_transit.bind(this, id, "done"),
then_transit.bind(this, id, "fail"));
} catch (error) {
if (this.state === id)
this.switchTo("fail", error);
} finally {
return;
}
}
} catch (error) {
value = error;
state = "fail";
}
}
this.switchTo(state, value);
}
},
resolve: function (value) {
this.transit("done", value);
},
reject: function (value) {
this.transit("fail", value);
},
then: function (done, fail) {
var then = {
next: new Deferred(),
done: done,
fail: fail
}
this.thens.push(then);
if (this.state)
this.asap();
return then.next.promise;
}
}
return function () {
return new Deferred();
}
})();
var promisesAplusTests = require("promises-aplus-tests");
promisesAplusTests({
deferred: deferred
}, {
reporter: "spec"
});