laissez-faire
Advanced tools
Comparing version 0.4.0 to 0.4.1
@@ -5,3 +5,3 @@ { | ||
"description": "A Promises/A implementation i.e a \"thenable\"", | ||
"version": "0.4.0", | ||
"version": "0.4.1", | ||
"keywords": ["promise", "async", "future", "control", "flow"], | ||
@@ -8,0 +8,0 @@ "dependencies": {}, |
{ | ||
"name": "laissez-faire", | ||
"version": "0.4.0", | ||
"version": "0.4.1", | ||
"description": "A promise implementation. Simple and fast", | ||
@@ -5,0 +5,0 @@ "main": "src/index.js", |
110
src/index.js
@@ -17,4 +17,2 @@ 'use strict'; | ||
Promise.is = isPromise | ||
Promise.prepareException = prepareException | ||
Promise.cancelException = cancelException | ||
@@ -27,3 +25,3 @@ /** | ||
*/ | ||
function prepareException (promise, e) { | ||
Promise.prepareException = function (promise, e) { | ||
// If we were to log the error immeadiatly a synchronously rejected promise might incorrectly have its error logged | ||
@@ -42,3 +40,3 @@ promise._throw = setTimeout(function () { | ||
*/ | ||
function cancelException (promise) { | ||
Promise.cancelException = function (promise) { | ||
clearTimeout(promise._throw); | ||
@@ -57,2 +55,4 @@ delete promise._throw | ||
p.reason = p.isRejected = e | ||
p.then = rejectedThen | ||
p.end = rejectedEnd | ||
return p | ||
@@ -70,2 +70,4 @@ } | ||
p.value = value | ||
p.then = resolvedThen | ||
p.end = resolvedEnd | ||
return p | ||
@@ -75,15 +77,2 @@ } | ||
/** | ||
* Create a child promise for an existing promise to later resolve | ||
* @param {Function} done | ||
* @param {Function} fail | ||
* @return {Promise} | ||
*/ | ||
function newNode (done, fail) { | ||
var p = new Promise | ||
p._success = done | ||
p._fail = fail | ||
return p | ||
} | ||
/** | ||
* Process the value safely and ensure that what is returned is represented via a new promise | ||
@@ -145,11 +134,7 @@ * | ||
var proto = Promise.prototype | ||
// Default states. By setting these we save some lookup time | ||
proto.isResolved = proto.isRejected = false | ||
proto.value = proto.reason = null | ||
/** | ||
* Default states | ||
* @type {Boolean} | ||
*/ | ||
proto.isResolved = false | ||
proto.isRejected = false | ||
/** | ||
* Create a follow up process | ||
@@ -163,18 +148,29 @@ * | ||
proto.then = function(done, fail) { | ||
var thenPromise | ||
var thenPromise | ||
// Create a child promise for an existing promise to later resolve | ||
this.children.push(thenPromise = new Promise) | ||
thenPromise._success = done | ||
thenPromise._fail = fail | ||
return thenPromise | ||
} | ||
if (this.isResolved) { | ||
thenPromise = run(done, this.value) | ||
} | ||
else if (this.isRejected) { | ||
cancelException(this) | ||
thenPromise = run(fail, this.reason) | ||
} | ||
else { | ||
this.children.push(thenPromise = newNode(done, fail)) | ||
} | ||
function resolvedThen (fn) { | ||
return run(fn, this.value) | ||
} | ||
return thenPromise | ||
function rejectedThen (_, fn) { | ||
Promise.cancelException(this) | ||
return run(fn, this.reason) | ||
} | ||
function resolvedEnd (fn) { | ||
fn && fn(this.value) | ||
} | ||
function rejectedEnd (_, fn) { | ||
if (!fn) throw this.reason | ||
Promise.cancelException(this) | ||
fn(this.reason) | ||
} | ||
/** | ||
@@ -188,23 +184,9 @@ * Like then but is designed for terminal operations. So any values generated will not be available for follow up and uncought errors will be thrown. Use this method in place of then when you don't plan to do anything with the stuff generated by your callbacks | ||
proto.end = function (done, fail) { | ||
if (this.isResolved) { | ||
done && done(this.value) | ||
} | ||
else if (this.isRejected) { | ||
if (fail) { | ||
Promise.cancelException(this) | ||
fail(this.reason) | ||
} | ||
else { | ||
throw this.reason | ||
} | ||
} | ||
else { | ||
// Queue an unsafe sudo-promise | ||
this.children.push({ | ||
// Handlers are bound to the assignment properties since these aren't run inside a try catch. Since there are no handlers any values will pass straight through to the resolvers | ||
resolve: done || noop, | ||
// Normally we don't assume reject is called with an Error instance by .end() promises are only ever called internally. Interestingly though if we didn't provide an error thrower as a backup we would still have the desired effect off throwing an error. However it would be a "no such method error" rather than the correct message which is undesirable | ||
reject: fail || function (e) { throw e } | ||
}) | ||
} | ||
// Queue a sudo-promise capable of throwing errors | ||
this.children.push({ | ||
// Handlers are bound to the assignment properties since these aren't run inside a try catch. Since there are no handlers any values will pass straight through to the resolvers | ||
resolve: done || noop, | ||
// Normally we don't assume reject is called with an Error instance by .end() promises are only ever called internally. Interestingly though if we didn't provide an error thrower as a backup we would still have the desired effect off throwing an error. However it would be a "no such method error" rather than the correct message which is undesirable | ||
reject: fail || function (e) { throw e } | ||
}) | ||
return this | ||
@@ -241,8 +223,16 @@ } | ||
if (value instanceof Error) return this.reject(value) | ||
// Change the state | ||
this.isResolved = true | ||
this.value = value | ||
// Change the behavior | ||
this.resolve = this.reject = noop | ||
this.then = resolvedThen | ||
this.end = resolvedEnd | ||
// Propagate the value to any queued promises. | ||
var children = this.children, | ||
len = children.length, | ||
i = -1 | ||
// Use a forward loop to maintain insertion order | ||
while (++i < len) propagate(children[i], children[i]._success, value) | ||
@@ -262,3 +252,7 @@ return this | ||
this.reason = e | ||
this.resolve = this.reject = noop | ||
this.then = rejectedThen | ||
this.end = rejectedEnd | ||
var children = this.children, | ||
@@ -272,3 +266,3 @@ len = children.length | ||
// Technically a promise can never throw an error since at any time in the future a user could add a child promise and handle the exception. However in practice the promise user probably has no plans of handling rejected promise later, so in most cases unhandled rejections are genuine errors. The following method provides a place for users to access these errors. | ||
prepareException(this, e) | ||
Promise.prepareException(this, e) | ||
} | ||
@@ -275,0 +269,0 @@ return this |
26096
284