Skip to content

Commit

Permalink
Handle changes to promises in Node v7+
Browse files Browse the repository at this point in the history
  • Loading branch information
othiym23 committed Apr 6, 2017
1 parent 1b94097 commit f11bebb
Show file tree
Hide file tree
Showing 2 changed files with 693 additions and 658 deletions.
39 changes: 25 additions & 14 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -343,16 +343,16 @@ if (instrumentPromise) {
* The async boundary in promises that must be patched is between the
* fulfillment of the promise and the execution of any callback that is waiting
* for that fulfillment to happen. This means that we need to trigger a create
* when accept or reject is called and trigger before, after and error handlers
* when resolve or reject is called and trigger before, after and error handlers
* around the callback execution. There may be multiple callbacks for each
* fulfilled promise, so handlers will behave similar to setInterval where
* there may be multiple before after and error calls for each create call.
*
* async-listener monkeypatching has one basic entry point: `wrapCallback`.
* `wrapCallback` should be called when create should be triggered and be
* passed a function to wrap, which will execute the body of the async work.
* The accept and reject calls can be modified fairly easily to call
* `wrapCallback`, but at the time of accept and reject all the work to be done
* The resolve and reject calls can be modified fairly easily to call
* `wrapCallback`, but at the time of resolve and reject all the work to be done
* on fulfillment may not be defined, since a call to then, chain or fetch can
* be made even after the promise has been fulfilled. To get around this, we
* create a placeholder function which will call a function passed into it,
Expand All @@ -364,22 +364,22 @@ if (instrumentPromise) {
* different ways depending on the return value of the callback. When the
* callback return a Promise, the new Promise is resolved asynchronously after
* the returned Promise has been also been resolved. When something other than
* a promise is resolved the accept call for the new Promise is put in the
* a promise is resolved the resolve call for the new Promise is put in the
* microtask queue and asynchronously resolved.
*
* Then must be wrapped so that its returned promise has a wrapper that can be
* used to invoke further continuations. This wrapper cannot be created until
* after the callback has run, since the callback may return either a promise
* or another value. Fortunately we already have a wrapper function around the
* callback we can use (the wrapper created by accept or reject).
* callback we can use (the wrapper created by resolve or reject).
*
* By adding an additional argument to this wrapper, we can pass in the
* returned promise so it can have its own wrapper appended. the wrapper
* function can the call the callback, and take action based on the return
* value. If a promise is returned, the new Promise can proxy the returned
* Promise's wrapper (this wrapper may not exist yet, but will by the time the
* wrapper needs to be invoked). Otherwise, a new wrapper can be create the
* same way as in accept and reject. Since this wrapper is created
* same way as in resolve and reject. Since this wrapper is created
* synchronously within another wrapper, it will properly appear as a
* continuation from within the callback.
*/
Expand Down Expand Up @@ -412,15 +412,15 @@ function wrapPromise() {

return promise;

function wrappedExecutor(accept, reject) {
function wrappedExecutor(resolve, reject) {
context = this;
args = [wrappedAccept, wrappedReject];

// These wrappers create a function that can be passed a function and an argument to
// call as a continuation from the accept or reject.
// call as a continuation from the resolve or reject.
function wrappedAccept(val) {
ensureAslWrapper(promise, false);
return accept(val);
return resolve(val);
}

function wrappedReject(val) {
Expand All @@ -433,14 +433,25 @@ function wrapPromise() {
util.inherits(wrappedPromise, Promise);

wrap(Promise.prototype, 'then', wrapThen);
// Node.js <v7 only, alias for .then
if (Promise.prototype.chain) {
wrap(Promise.prototype, 'chain', wrapThen);
}

var PromiseMethods = ['accept', 'all', 'defer', 'race', 'reject', 'resolve'];

PromiseMethods.forEach(function(key) {
wrappedPromise[key] = Promise[key];
var PromiseFunctions = [
'all',
'race',
'reject',
'resolve',
'accept', // Node.js <v7 only
'defer' // Node.js <v7 only
];

PromiseFunctions.forEach(function(key) {
// don't break `in` by creating a key for undefined entries
if (typeof Promise[key] === 'function') {
wrappedPromise[key] = Promise[key];
}
});

global.Promise = wrappedPromise;
Expand Down Expand Up @@ -487,7 +498,7 @@ function wrapPromise() {
return next;

// wrap callbacks (success, error) so that the callbacks will be called as a
// continuations of the accept or reject call using the __asl_wrapper created above.
// continuations of the resolve or reject call using the __asl_wrapper created above.
function bind(fn) {
if (typeof fn !== 'function') return fn;
return wrapCallback(function (val) {
Expand Down
Loading

0 comments on commit f11bebb

Please sign in to comment.