$ cnpm install promise-nodeify
Call a Node-style callback with the resolution value or rejection cause of a Promise without the common pitfalls.
var promiseNodeify = require('promise-nodeify');
// Function which returns a Promise
function returnsPromise() {
return new Promise(function(resolve, reject) {
resolve(42);
});
}
// Function which takes an optional node-style callback
function takesCallback(callback) {
var promise = returnsPromise();
// if callback is not a function, promise is returned as-is
// otherwise callback will be called when promise is resolved or rejected
// promise will not cause unhandledRejection if callback is a function
return promiseNodeify(promise, callback);
}
The important features of nodeify as compared to naive implementations:
Error for falsey rejection causes. Since Promises may resolve or
reject without providing a value or cause, the callback would have no way to
distinguish success from failure. This module ensures the error argument is
always truthy, substituting an Error when the rejection cause is falsey
(and passing the original value as the .cause property, as bluebird does).uncaughtException as they would for
other callbacks (unlike passing callback to .then, which causes
unhandledRejection or swallows them).unhandledRejection
(unlike if the promise were ignored and callback invoked directly).unhandledRejections and multiple threads of control - or returning
the result passing the callback to .then, which resolves to the callback
result).This module provides similar behavior to several popular promise libraries in a promise-library-agnostic way which only requires the ES6 promise functionality subset. However, these existing implementations differ in subtle ways. A brief comparison:
| Behavior | this module | bluebird #asCallback |
es-nodeify | nodeify | then #nodeify |
Un-thenify1 | when.js .bindCallback |
|---|---|---|---|---|---|---|---|
returns (with function) |
undefined |
this Promise2 |
undefined |
Promise<undefined> |
undefined |
undefined |
when(promise) |
| returns (with falsey) | promise |
promise |
promise |
Promise<undefined> |
promise |
undefined with unhandledRejection |
when(promise) |
| returns (non-function) | promise |
promise |
undefined with unhandledRejection |
promise |
promise |
undefined with unhandledRejection |
when(promise) with uncaughtException |
| callback exception | uncaughtException |
uncaughtException |
unhandledRejection |
uncaughtException |
uncaughtException |
unhandledRejection |
uncaughtException |
| falsey cause | Error with .cause |
Error with .cause3 |
Error |
falsey cause | falsey cause | TypeError |
falsey cause |
| reject argument length | 1 | 1 | 1 | 1 | 1 | 1 | 2 |
| resolve argument length | 2 | undefined ? 1 : 24 |
2 | 2 | 2 | 2 | 2 |
| extra argument | ignored | options5 | ignored | ignored | this of callback |
ignored | ignored |
Notes:
spread boolean option to
pass Array values as separate arguments to callback.These benchmarks were done using the benchmark/index.js
script on an Intel(R) Core(TM) i5-3320M CPU @ 2.60GHz with Node v4.3.1 on
Linux and the following module versions:
| Module | Version |
|---|---|
benchmark |
2.1.0 |
bluebird |
3.3.3 |
cli-table |
0.3.1 |
es-nodeify |
1.0.0 |
microtime |
2.0.0 |
native-promise-only |
0.8.1 |
nodeify |
1.0.0 |
pinkie-promise |
2.0.0 |
promise |
7.1.1 |
q |
1.4.1 |
rsvp |
3.2.1 |
unthenify |
1.0.1 |
when |
3.7.7 |
Performance (in operations per second) of calling nodeify on a resolved
promise (larger is better):
| ops/sec | bluebird | native | npo | pinkie | q | rsvp | then | when |
|---|---|---|---|---|---|---|---|---|
| bluebird#nodeify | 1,922,721.987 | TypeError | TypeError | TypeError | TypeError | TypeError | TypeError | TypeError |
| es-nodeify | 1,345,702.588 | 506,103.345 | 510,887.217 | 534,013.961 | 68,915.816 | 1,974,250.737 | 2,096,468.119 | 1,756,177.934 |
| nodeify | 147,481.019 | 251,414.264 | 251,535.145 | 253,880.998 | 58,504.098 | 1,355,812.482 | 1,102,467.756 | 1,160,226.624 |
| promiseNodeify | 1,586,092.279 | 481,842.79 | 452,529.247 | 455,657.062 | 66,045.273 | 2,108,607.126 | 2,370,823.723 | 1,942,722.539 |
| then#nodeify | 136,716.987 | 202,670.23 | 225,297.257 | 231,042.286 | 56,384.953 | 764,719.55 | 1,320,158.92 | 739,062.155 |
| unthenify | 100,638.922 | 79,097.99 | 80,488.25 | 78,298.365 | 40,683.82 | 103,125.162 | 100,618.139 | 101,887.997 |
| when.bindCallback | 823.326 | 856.669 | 842.975 | 834.864 | 748.669 | 847.556 | 850.316 | 839.995 |
Performance (in operations per second) of calling nodeify on a rejected
promise (larger is better):
| ops/sec | bluebird | native | npo | pinkie | q | rsvp | then | when |
|---|---|---|---|---|---|---|---|---|
| bluebird#nodeify | 1,889,496.469 | TypeError | TypeError | TypeError | TypeError | TypeError | TypeError | TypeError |
| es-nodeify | 1,247,981.228 | 520,349.959 | 455,337.77 | 466,964.692 | 64,703.247 | 2,182,281.005 | 2,062,330.035 | 1,889,184.935 |
| nodeify | 147,454.87 | 325,956.476 | 326,958.556 | 325,971.637 | 53,878.098 | 1,232,726.201 | 952,338.091 | 926,626.949 |
| promiseNodeify | 1,170,756.604 | 465,186.326 | 478,343.59 | 489,024.094 | 62,905.801 | 2,097,277.371 | 1,928,682.943 | 1,497,451.328 |
| then#nodeify | 131,588.987 | 241,627.02 | 246,557.24 | 245,427.553 | 49,655.492 | 684,232.864 | 1,178,175.996 | 634,041.464 |
| unthenify | 96,359.916 | 82,291.679 | 82,507.055 | 83,324.584 | 38,842.741 | 96,432.332 | 97,113.05 | 99,892.099 |
| when.bindCallback | 822.083 | 837.698 | 848.358 | 851.348 | 789.546 | 854.184 | 844.102 | 851.644 |
This package can be installed using npm by running:
npm install promise-nodeify
This package can be installed using bower by running:
bower install promise-nodeify
This module is also available with a UMD
loader, both minified and un-minified, in the dist directory. They
can be downloaded, self-hosted, or loaded from a CDN. To use the RawGit
CDN, use the following (X)HTML:
<script src="https://cdn.rawgit.com/kevinoid/promise-nodeify/v0.1.0/dist/promise-nodeify.min.js"></script>
Promise.prototype.nodeifyIf the behavior differences discussed in the Behavior
Comparison section (and any future differences which
may occur) are not significant to your use case and you are interested in
taking advantage of the potential performance
benefit of the implementation provided by the
promise library, use the .delegated function:
// Using .delegated delegates to .nodeify on the promise argument when present
var promiseNodeify = require('promise-nodeify').delegated;
function returnsPromise() {
return new Promise(function(resolve, reject) {
resolve(42);
});
}
function takesCallback(callback) {
var promise = returnsPromise();
return promiseNodeify(promise, callback);
}
Promise.prototype.nodeifyTo polyfill the .nodeify (or .asCallback) method for a Promise library,
assign the .nodeifyThis function to Promise.prototype.nodeify as follows:
Promise.prototype.nodeify = require('promise-nodeify').nodeifyThis;
function returnsPromise() {
return new Promise(function(resolve, reject) {
resolve(42);
});
}
function takesCallback(callback) {
var promise = returnsPromise();
return promise.nodeify(callback);
}
More examples can be found in the test specifications.
For a description of the available functions and their arguments, see the API Documentation.
Contributions are welcome and very much appreciated! Please add tests to
cover any changes and ensure npm test passes.
The dist files are only updated for releases, so please don't include them
in pull requests.
If the desired change is large, complex, backwards-incompatible, can have significantly differing implementations, or may not be in scope for this project, opening an issue before writing the code can avoid frustration and save a lot of time and effort.
This package is available under the terms of the MIT License.
Copyright 2013 - present © cnpmjs.org | Home |