laissez-faire
Advanced tools
Comparing version 0.6.5 to 0.7.0
@@ -5,3 +5,3 @@ { | ||
"description": "A Promises/A implementation i.e a \"thenable\"", | ||
"version": "0.6.4", | ||
"version": "0.7.0", | ||
"keywords": ["promise", "async", "future", "control", "flow"], | ||
@@ -8,0 +8,0 @@ "dependencies": {}, |
{ | ||
"name": "laissez-faire", | ||
"version": "0.6.5", | ||
"version": "0.7.0", | ||
"description": "A promise implementation. Simple and fast", | ||
@@ -9,4 +9,7 @@ "main": "src/index.js", | ||
}, | ||
"dependencies": { | ||
"jkroso-emitter": "" | ||
}, | ||
"devDependencies": { | ||
"gluejs": "*", | ||
"bigfile": "", | ||
"mocha": "*", | ||
@@ -18,3 +21,2 @@ "sinon": "*", | ||
"scripts": { | ||
"build": "node ./glue.js", | ||
"test": "node tests/" | ||
@@ -35,4 +37,3 @@ }, | ||
"author": "Jakeb Rosoman", | ||
"license": "MIT", | ||
"dependencies": {} | ||
"license": "MIT" | ||
} |
329
src/index.js
@@ -5,2 +5,4 @@ exports = module.exports = Promise | ||
* Promise class | ||
* | ||
* var promise = new Promise | ||
*/ | ||
@@ -10,24 +12,32 @@ function Promise () {this.length = 0} | ||
/** | ||
* Dafualt uncought error handler. It will wait 1 second for you to handle the error before logging it to the console. Feel free to replace this function with one you find more useful. Its purely a debugging feature. Technically promises throw unhandled exceptions. They just sit around waiting for you to handle them | ||
* Dafualt uncought error handler. It will wait 1 second for you to | ||
* handle the error before logging it to the console. Feel free to replace | ||
* this function with one you find more useful. Its purely a debugging | ||
* feature. Technically promises throw unhandled exceptions. They just sit | ||
* around waiting for you to handle them | ||
* | ||
* @param {Promise} promise The promise that was rejected without an error handler or child promise | ||
* @param {Error} e The Error instance emitted by the promise | ||
* @param {Error} e The Error instance emitted by the promise | ||
*/ | ||
Promise.prepareException = function (promise, e) { | ||
// If we were to log the error immeadiatly a synchronously rejected promise might incorrectly have its error logged | ||
promise._throw = setTimeout(function () { | ||
console.warn(promise, | ||
'\nPromise error ('+(e.message.replace(/^Error:\s+/, ''))+') not handled within 1 second' | ||
+ e.stack.toString().replace(/^.*/, '')) | ||
}, 1000) | ||
exports.prepareException = function (promise, e) { | ||
promise._throw = setTimeout(function () { | ||
if (e instanceof Error) { | ||
e.message += ' (Rethrown from rejected promise)' | ||
throw e | ||
} else { | ||
console.warn('Not handled within 1 second: ', e) | ||
} | ||
}, 1000) | ||
} | ||
/** | ||
* Sometimes error handlers may be added after a promise has been rejected. If you would like to cancel any undhandled exception handling logging logic you can do so by replaceing this function | ||
* Sometimes error handlers may be added after a promise has been rejected. | ||
* If you would like to cancel any undhandled exception handling logging | ||
* logic you can do so by replaceing this function | ||
* | ||
* @param {Promise} promise The promise which previously failed without error handlers | ||
*/ | ||
Promise.cancelException = function (promise) { | ||
clearTimeout(promise._throw); | ||
delete promise._throw | ||
exports.cancelException = function (promise) { | ||
clearTimeout(promise._throw); | ||
delete promise._throw | ||
} | ||
@@ -42,7 +52,7 @@ | ||
function newRejected (e) { | ||
var p = new Promise | ||
p.reason = e | ||
p.then = rejectedThen | ||
p.end = rejectedEnd | ||
return p | ||
var p = new Promise | ||
p.reason = e | ||
p.then = rejectedThen | ||
p.end = rejectedEnd | ||
return p | ||
} | ||
@@ -57,7 +67,7 @@ | ||
function newFulfilled (value) { | ||
var p = new Promise | ||
p.value = value | ||
p.then = resolvedThen | ||
p.end = resolvedEnd | ||
return p | ||
var p = new Promise | ||
p.value = value | ||
p.then = resolvedThen | ||
p.end = resolvedEnd | ||
return p | ||
} | ||
@@ -70,16 +80,17 @@ | ||
* @param {Any} value The result from computing the previous promise | ||
* @api private | ||
*/ | ||
function run (fn, value) { | ||
var result | ||
try { | ||
result = fn(value) | ||
} catch (e) { | ||
return newRejected(e) | ||
} | ||
if (isPromise(result)) { | ||
// No need to create a new promise if we already have one | ||
return result === value ? result.then() : result | ||
} else { | ||
return newFulfilled(result) | ||
} | ||
var result | ||
try { | ||
result = fn(value) | ||
} catch (e) { | ||
return newRejected(e) | ||
} | ||
if (isPromise(result)) { | ||
// No need to create a new promise if we already have one | ||
return result === value ? result.then() : result | ||
} else { | ||
return newFulfilled(result) | ||
} | ||
} | ||
@@ -93,18 +104,19 @@ | ||
* @param {Any} value The input | ||
* @api private | ||
*/ | ||
function propagate (promise, fn, value) { | ||
try { | ||
value = fn(value) | ||
} catch (e) { | ||
return promise.reject(e) | ||
} | ||
if (isPromise(value)) { | ||
// prefer .end() | ||
value[typeof value.end === 'function' ? 'end': 'then']( | ||
function (val) {promise.resolve(val)}, | ||
function (err) {promise.reject(err) }) | ||
} | ||
else { | ||
promise.resolve(value) | ||
} | ||
try { | ||
value = fn(value) | ||
} catch (e) { | ||
return promise.reject(e) | ||
} | ||
if (isPromise(value)) { | ||
// prefer .end() | ||
value[typeof value.end === 'function' ? 'end': 'then']( | ||
function (val) {promise.resolve(val)}, | ||
function (err) {promise.reject(err) }) | ||
} | ||
else { | ||
promise.resolve(value) | ||
} | ||
} | ||
@@ -114,14 +126,23 @@ | ||
function isPromise (item) { | ||
return item && typeof item.then === 'function' | ||
return item && typeof item.then === 'function' | ||
} | ||
var proto = Promise.prototype = Object.create( | ||
require('jkroso-emitter').prototype, | ||
{constructor:{value:Promise}} | ||
require('jkroso-emitter').prototype, | ||
{constructor:{value:Promise}} | ||
) | ||
// Default states. | ||
proto.value = proto.reason = undefined | ||
proto.value = proto.reason = null | ||
/** | ||
* Create a follow up process | ||
* | ||
* promise.then( | ||
* function(value){ | ||
* return value | ||
* }, | ||
* function(error){ | ||
* return correction | ||
* } | ||
* ) | ||
* | ||
@@ -134,23 +155,26 @@ * @param {Function} done | ||
proto.then = function(done, fail) { | ||
var thenPromise | ||
this[this.length++] = (thenPromise = new Promise) | ||
thenPromise._success = done | ||
thenPromise._fail = fail | ||
return thenPromise | ||
var thenPromise | ||
this[this.length++] = (thenPromise = new Promise) | ||
thenPromise._success = done | ||
thenPromise._fail = fail | ||
return thenPromise | ||
} | ||
// Alternative then methods | ||
function resolvedThen (fn) { | ||
return fn | ||
? run(fn, this.value) | ||
: newFulfilled(this.value) | ||
return fn | ||
? run(fn, this.value) | ||
: newFulfilled(this.value) | ||
} | ||
function rejectedThen (_, fn) { | ||
Promise.cancelException(this) | ||
return fn | ||
? run(fn, this.reason) | ||
: newRejected(this.reason) | ||
Promise.cancelException(this) | ||
return fn | ||
? run(fn, this.reason) | ||
: newRejected(this.reason) | ||
} | ||
/** | ||
* Like then but is designed for terminal operations. So any values generated will not be available for follow up and uncaught 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 | ||
* Like then but is designed for terminal operations. So any values generated will | ||
* not be available for follow up and uncaught 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 | ||
* | ||
@@ -162,21 +186,26 @@ * @param {Function} done | ||
proto.end = function (done, fail) { | ||
// Queue a sudo-promise capable of throwing errors | ||
this[this.length++] = { | ||
// Handlers are bound to the assignment properties since these aren't run inside a try catch. Having no handlers is fine, the values will just pass straight through to the resolvers. | ||
resolve: done || noop, | ||
// Interestingly if we didn't provide an error thrower as a backup we would still be guaranteed to throw at the right time. However it would be "no such method" instead of the users error. | ||
reject: fail || function (e) { throw e } | ||
} | ||
return this | ||
// Queue a sudo-promise capable of throwing errors | ||
this[this.length++] = { | ||
// Handlers are bound to the assignment properties since these aren't run inside a try catch. Having no handlers is fine, the values will just pass straight through to the resolvers. | ||
resolve: done || noop, | ||
// Interestingly if we didn't provide an error thrower as a backup we would still be guaranteed to throw at the right time. However it would be "no such method" instead of the users error. | ||
reject: fail || function (e) {throw e} | ||
} | ||
return this | ||
} | ||
/** | ||
* @alias end | ||
*/ | ||
proto.stub = proto.throw = function (done, fail) {return this.end(done, fail)} | ||
// Alternative `end` methods for when the state of the promise changes | ||
function resolvedEnd (fn) { | ||
fn && fn(this.value) | ||
return this | ||
fn && fn(this.value) | ||
return this | ||
} | ||
function rejectedEnd (_, fn) { | ||
Promise.cancelException(this) | ||
if (!fn) throw this.reason | ||
fn(this.reason) | ||
return this | ||
Promise.cancelException(this) | ||
if (!fn) throw this.reason | ||
fn(this.reason) | ||
return this | ||
} | ||
@@ -190,7 +219,9 @@ | ||
proto.fail = function (fn) { | ||
return this.end(null, fn) | ||
return this.end(null, fn) | ||
} | ||
/** | ||
* If you pass callbacks it will act like .end otherwise it will attempt to return its resolution synchronously | ||
* If you pass callbacks it will act like .end otherwise it will | ||
* attempt to return its resolution synchronously | ||
* | ||
* @param {Function} done optional | ||
@@ -201,8 +232,8 @@ * @param {Function} fail optional | ||
proto.valueOf = function (done, fail) { | ||
if (done || fail) return this.end(done, fail) | ||
switch (this.then) { | ||
case resolvedThen: return this.value | ||
case rejectedThen: return this.reason | ||
default: return this | ||
} | ||
if (done || fail) return this.end(done, fail) | ||
switch (this.then) { | ||
case resolvedThen: return this.value | ||
case rejectedThen: return this.reason | ||
default: return this | ||
} | ||
} | ||
@@ -216,3 +247,3 @@ | ||
proto.otherwise = function (errback) { | ||
return this.then(null, errback) | ||
return this.then(null, errback) | ||
} | ||
@@ -226,3 +257,3 @@ | ||
proto.always = function (callback) { | ||
return this.then(callback, callback) | ||
return this.then(callback, callback) | ||
} | ||
@@ -236,6 +267,24 @@ | ||
proto.finish = function (callback) { | ||
return this.end(callback, callback) | ||
return this.end(callback, callback) | ||
} | ||
/** | ||
* Allows the use of node style callbacks | ||
* @param {Function} callback [err, value] | ||
* @return {Promise} | ||
*/ | ||
proto.node = function (callback) { | ||
return this.then(function (val) {return callback(null, val)}, callback) | ||
} | ||
/** | ||
* Provides simple access to the promises value via a node style callback | ||
* @param {Function} callback [error, value] | ||
* @return {Self} | ||
*/ | ||
proto.nend = function (callback) { | ||
return this.end(function (val) {callback(null, val)}, callback) | ||
} | ||
/** | ||
* Give the promise it's value and trigger all process branches | ||
@@ -247,23 +296,22 @@ * | ||
proto.resolve = function (value) { | ||
// Change the state | ||
this.value = value | ||
// Change the behavior. In a parallel universe this is just a matter of swapping the prototype. | ||
this.resolve = this.reject = noop | ||
this.then = resolvedThen | ||
this.end = resolvedEnd | ||
// Change the state | ||
this.value = value | ||
// Change the behavior. In a parallel universe this is just a matter of swapping the prototype. | ||
this.resolve = this.reject = noop | ||
this.then = resolvedThen | ||
this.end = resolvedEnd | ||
// Propagate the value to any queued promises. | ||
var child, i = 0 | ||
// Use a forward loop to maintain insertion order | ||
while (child = this[i++]) { | ||
if (child._success) propagate(child, child._success, value) | ||
else child.resolve(value) | ||
} | ||
return this | ||
// Propagate the value to any queued promises. | ||
var child, i = 0 | ||
// Use a forward loop to maintain insertion order | ||
while (child = this[i++]) { | ||
if (child._success) propagate(child, child._success, value) | ||
else child.resolve(value) | ||
} | ||
return this | ||
} | ||
/** | ||
* Delegates to the correct function, resolve or reject, depending on the value given | ||
* | ||
* Delegates to resolve or reject, depending on the value given | ||
* @param {Any} unknown | ||
@@ -273,3 +321,3 @@ * @return {self} | ||
proto.assign = function (unknown) { | ||
return this[unknown instanceof Error ? 'reject' : 'resolve'](unknown) | ||
return this[unknown instanceof Error ? 'reject' : 'resolve'](unknown) | ||
} | ||
@@ -284,20 +332,20 @@ | ||
proto.reject = function (e) { | ||
this.reason = e | ||
this.resolve = this.reject = noop | ||
this.then = rejectedThen | ||
this.end = rejectedEnd | ||
var i = 0, child | ||
if (child = this[i]) { | ||
do { | ||
if (child._fail) propagate(child, child._fail, e) | ||
else child.reject(e) | ||
} while (child = this[++i]) | ||
} | ||
else { | ||
// If a promise is rejected without any child promises we might have a genuine error. The following method provides a place for users to access these errors. | ||
Promise.prepareException(this, e) | ||
} | ||
return this | ||
this.reason = e | ||
this.resolve = this.reject = noop | ||
this.then = rejectedThen | ||
this.end = rejectedEnd | ||
var i = 0, child | ||
if (child = this[i]) { | ||
do { | ||
if (child._fail) propagate(child, child._fail, e) | ||
else child.reject(e) | ||
} while (child = this[++i]) | ||
} | ||
else { | ||
// If a promise is rejected without any child promises we might have a genuine error. The following method provides a place for users to access these errors. | ||
Promise.prepareException(this, e) | ||
} | ||
return this | ||
} | ||
@@ -307,2 +355,10 @@ | ||
* Create a promise destined to resolve with a given value | ||
* | ||
* function () { | ||
* var result = 3 | ||
* return promise.then(function(value){ | ||
* // something side effect | ||
* }).yeild(result) | ||
* } | ||
* | ||
* @param {Any} value | ||
@@ -312,5 +368,12 @@ * @return {Promise} | ||
proto.yeild = function (value) { | ||
return this.then(function () {return value}) | ||
return this.then(function () {return value}) | ||
} | ||
proto.isRejected = function () { | ||
return this.then === rejectedThen | ||
} | ||
proto.isFulfilled = function () { | ||
return this.then === resolvedThen | ||
} | ||
/** | ||
@@ -322,9 +385,9 @@ * Generate a safe interface for a promise | ||
proto.proxy = function () { | ||
var self = this | ||
return Object.create(null, {then: {value:function(a,b){ | ||
// The returned promise does not need to be proxied since the goblin owns this one | ||
return self.then(a,b) | ||
}}}) | ||
var self = this | ||
return Object.create(null, {then: {value:function(a,b){ | ||
// The returned promise does not need to be proxied since the goblin owns this one | ||
return self.then(a,b) | ||
}}}) | ||
} | ||
function noop () {} |
Wildcard dependency
QualityPackage has a dependency with a floating version range. This can cause issues if the dependency publishes a new major version.
Found 1 instance in 1 package
No README
QualityPackage does not have a README. This may indicate a failed publish or a low quality package.
Found 1 instance in 1 package
48634
7
386
429
1
+ Addedjkroso-emitter@
+ Addedjkroso-emitter@0.4.0(transitive)