Comparing version 0.4.0 to 0.5.0-alpha
103
kew.js
@@ -24,3 +24,61 @@ | ||
var nextTick = process.nextTick | ||
/** | ||
* All callback execution should go through this function. While the | ||
* implementation below is simple, it can be replaced with more sophisticated | ||
* implementations that enforce QoS on the event loop. | ||
* | ||
* @param {Promise} defer | ||
* @param {Function} callback | ||
* @param {Object} scope | ||
* @param {Array} args | ||
*/ | ||
function nextTickCallback (defer, callback, scope, args) { | ||
try { | ||
defer.resolve(callback.apply(scope, args)) | ||
} catch (thrown) { | ||
defer.reject(thrown) | ||
} | ||
} | ||
/** | ||
* Used for accessing the nextTick function from outside the kew module. | ||
* | ||
* @return {Function} | ||
*/ | ||
function getNextTickFunction () { | ||
return nextTick | ||
} | ||
/** | ||
* Used for overriding the nextTick function from outside the kew module so that | ||
* the user can plug and play lower level schedulers | ||
* @param {Function} fn | ||
*/ | ||
function setNextTickFunction (fn) { | ||
nextTick = fn | ||
} | ||
/** | ||
* Keep track of the number of promises that are rejected along side | ||
* the number of rejected promises we call _failFn on so we can look | ||
* for leaked rejections. | ||
*/ | ||
function PromiseStats() { | ||
this.errorsEmitted = 0 | ||
this.errorsHandled = 0 | ||
} | ||
var stats = new PromiseStats() | ||
Promise.prototype._handleError = function () { | ||
if (!this._errorHandled) { | ||
stats.errorsHandled++ | ||
this._errorHandled = true | ||
} | ||
} | ||
/** | ||
* Specify that the current promise should have a specified context | ||
@@ -106,2 +164,3 @@ * @param {*} context context | ||
for (i = 0; i < this._promises.length; i += 1) { | ||
this._promises[i]._useContext(this._nextContext) | ||
this._promises[i]._withInput(data) | ||
@@ -124,4 +183,6 @@ } | ||
this._error = e | ||
stats.errorsEmitted++ | ||
if (this._ended) { | ||
this._handleError() | ||
process.nextTick(function onPromiseThrow() { | ||
@@ -139,3 +200,5 @@ throw e | ||
if (this._promises) { | ||
this._handleError() | ||
for (i = 0; i < this._promises.length; i += 1) { | ||
this._promises[i]._useContext(this._nextContext) | ||
this._promises[i]._withError(e) | ||
@@ -272,2 +335,3 @@ } | ||
if (this._error) { | ||
this._handleError() | ||
throw this._error | ||
@@ -337,8 +401,6 @@ } | ||
if (this._successFn) { | ||
try { | ||
this.resolve(this._call(this._successFn, [data, this._currentContext])) | ||
} catch (e) { | ||
this.reject(e) | ||
} | ||
} else this.resolve(data) | ||
this._nextTick(this._successFn, [data, this._currentContext]) | ||
} else { | ||
this.resolve(data) | ||
} | ||
@@ -357,8 +419,6 @@ // context is no longer needed | ||
if (this._failFn) { | ||
try { | ||
this.resolve(this._call(this._failFn, [e, this._currentContext])) | ||
} catch (thrown) { | ||
this.reject(thrown) | ||
} | ||
} else this.reject(e) | ||
this._nextTick(this._failFn, [e, this._currentContext]) | ||
} else { | ||
this.reject(e) | ||
} | ||
@@ -373,10 +433,9 @@ // context is no longer needed | ||
* @param {Array} args | ||
* @return {*} | ||
* @private | ||
*/ | ||
Promise.prototype._call = function (fn, args) { | ||
Promise.prototype._nextTick = function (fn, args) { | ||
if (this._boundArgs) { | ||
args = this._boundArgs.concat(args) | ||
} | ||
return fn.apply(this._scope, args) | ||
nextTick(nextTickCallback.bind(null, this, fn, this._scope, args)) | ||
} | ||
@@ -399,2 +458,5 @@ | ||
} else if (this._error) { | ||
// We can't rely on _withError() because it's called on the chained promises | ||
// and we need to use the source's _errorHandled state | ||
this._handleError() | ||
promise._withError(this._error) | ||
@@ -671,9 +733,3 @@ } else if (!this._promises) { | ||
var defer = new Promise() | ||
process.nextTick(function onNextTick() { | ||
try { | ||
defer.resolve(fn.apply(undefined, rootArgs)) | ||
} catch (e) { | ||
defer.reject(e) | ||
} | ||
}) | ||
nextTick(nextTickCallback.bind(null, defer, fn, undefined, rootArgs)) | ||
return defer | ||
@@ -732,4 +788,7 @@ } | ||
, reject: reject | ||
, stats: stats | ||
, allSettled: allSettled | ||
, Promise: Promise | ||
, getNextTickFunction: getNextTickFunction | ||
, setNextTickFunction: setNextTickFunction | ||
} |
{ | ||
"name": "kew", | ||
"description": "a lightweight promise library for node", | ||
"version": "0.4.0", | ||
"version": "0.5.0-alpha", | ||
"homepage": "https://github.com/Obvious/kew", | ||
@@ -6,0 +6,0 @@ "authors": [ |
@@ -246,2 +246,3 @@ var Q = require('../kew') | ||
exports.testChainedEndUncaught = function (test) { | ||
var uncaughtErrors = 0 | ||
var errs = [] | ||
@@ -252,6 +253,11 @@ errs.push(new Error('nope 1')) | ||
process.on('uncaughtException', function (e) { | ||
test.equal(e, errs.shift(), "Error should be uncaught") | ||
if (errs.length === 0) test.done() | ||
}) | ||
var cb = function (e) { | ||
uncaughtErrors++ | ||
if (e === errs[2]) { | ||
test.equal(uncaughtErrors, 3, "Errors should be uncaught") | ||
process.removeListener('uncaughtException', cb) | ||
test.done() | ||
} | ||
} | ||
process.on('uncaughtException', cb) | ||
@@ -258,0 +264,0 @@ var defer = Q.defer() |
@@ -7,5 +7,6 @@ var Q = require('../kew') | ||
detectedScope = this | ||
}).then(function () { | ||
test.ok(Q.isPromise(detectedScope), 'then() should be called in context of promise') | ||
test.done() | ||
}) | ||
test.ok(Q.isPromise(detectedScope), 'then() should be called in context of promise') | ||
test.done() | ||
} | ||
@@ -17,5 +18,6 @@ | ||
detectedScope = this | ||
}).then(function () { | ||
test.ok(Q.isPromise(detectedScope), 'fail() should be called in context of promise') | ||
test.done() | ||
}) | ||
test.ok(Q.isPromise(detectedScope), 'fail() should be called in context of promise') | ||
test.done() | ||
} | ||
@@ -28,5 +30,6 @@ | ||
detectedScope = scope | ||
}, scope) | ||
test.ok(detectedScope === scope, 'thenScoped() should be called in context of scope') | ||
test.done() | ||
}, scope).then(function () { | ||
test.ok(detectedScope === scope, 'thenScoped() should be called in context of scope') | ||
test.done() | ||
}) | ||
} | ||
@@ -39,5 +42,6 @@ | ||
detectedScope = scope | ||
}, scope) | ||
test.equal(detectedScope, scope, 'failBound() should be called in context of scope') | ||
test.done() | ||
}, scope).then(function () { | ||
test.equal(detectedScope, scope, 'failBound() should be called in context of scope') | ||
test.done() | ||
}) | ||
} | ||
@@ -54,6 +58,7 @@ | ||
detectedScope = scope | ||
}, scope, 1, 2, 3) | ||
test.ok(detectedScope === scope, 'failScoped() should be called in context of scope') | ||
test.done() | ||
}, scope, 1, 2, 3).then(function () { | ||
test.ok(detectedScope === scope, 'failScoped() should be called in context of scope') | ||
test.done() | ||
}) | ||
} | ||
@@ -26,2 +26,46 @@ var Q = require('../kew') | ||
// Test Q.stats | ||
exports.testQStatistics = function (test) { | ||
var err = new Error("hello") | ||
var errorsEmitted = Q.stats.errorsEmitted | ||
var errorsHandled = Q.stats.errorsHandled | ||
var rejected = Q.reject(err) | ||
test.equal(errorsEmitted + 1, Q.stats.errorsEmitted, "One additional error emitted") | ||
test.equal(errorsHandled, Q.stats.errorsHandled, "Error hasn't been handled yet") | ||
rejected.fail(function (e) { | ||
test.equal(e, err, "Promise successfully failed") | ||
test.equal(errorsEmitted + 1, Q.stats.errorsEmitted, "One additional error emitted") | ||
test.equal(errorsHandled + 1, Q.stats.errorsHandled, "One additional error handled") | ||
}) | ||
rejected.fail(function (e) { | ||
test.equal(e, err, "Promise successfully failed") | ||
test.equal(errorsEmitted + 1, Q.stats.errorsEmitted, "One additional error emitted") | ||
test.equal(errorsHandled + 1, Q.stats.errorsHandled, "Only count error handling once") | ||
}) | ||
test.done() | ||
} | ||
exports.testQDeferredStatistics = function (test) { | ||
var err = new Error("hello") | ||
var errorsEmitted = Q.stats.errorsEmitted | ||
var errorsHandled = Q.stats.errorsHandled | ||
var deferred = Q.defer() | ||
deferred.fail(function (e) { | ||
test.equal(e, err, "Promise successfully failed") | ||
test.equal(errorsEmitted + 1, Q.stats.errorsEmitted, "One additional error emitted") | ||
test.equal(errorsHandled + 1, Q.stats.errorsHandled, "One additional error handled") | ||
test.done() | ||
}) | ||
var rejected = deferred.reject(err) | ||
} | ||
// test Q.all with an empty array | ||
@@ -28,0 +72,0 @@ exports.testQEmptySuccess = function (test) { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
72010
13
1763
1