Skip to content

Commit

Permalink
Add support for AsyncResource
Browse files Browse the repository at this point in the history
Fixes #1403.
  • Loading branch information
Sebmaster authored and petkaantonov committed May 25, 2019
1 parent c70d516 commit e1c4a91
Show file tree
Hide file tree
Showing 8 changed files with 224 additions and 54 deletions.
25 changes: 13 additions & 12 deletions src/debuggability.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use strict";
module.exports = function(Promise, Context) {
var getDomain = Promise._getDomain;
var getContext = Promise._getContext;
var async = Promise._async;
var Warning = require("./errors").Warning;
var util = require("./util");
Expand Down Expand Up @@ -104,19 +104,13 @@ Promise.prototype._warn = function(message, shouldUseOwnTrace, promise) {
};

Promise.onPossiblyUnhandledRejection = function (fn) {
var domain = getDomain();
possiblyUnhandledRejection =
typeof fn === "function" ? (domain === null ?
fn : util.domainBind(domain, fn))
: undefined;
var context = getContext();
possiblyUnhandledRejection = util.contextBind(context, fn);
};

Promise.onUnhandledRejectionHandled = function (fn) {
var domain = getDomain();
unhandledRejectionHandled =
typeof fn === "function" ? (domain === null ?
fn : util.domainBind(domain, fn))
: undefined;
var context = getContext();
unhandledRejectionHandled = util.contextBind(context, fn);
};

var disableLongStackTraces = function() {};
Expand Down Expand Up @@ -308,6 +302,9 @@ Promise.config = function(opts) {
Promise.prototype._fireEvent = defaultFireEvent;
}
}
if ("asyncHooks" in opts) {
config.asyncHooks = opts.asyncHooks;
}
return Promise;
};

Expand Down Expand Up @@ -933,12 +930,16 @@ var config = {
warnings: warnings,
longStackTraces: false,
cancellation: false,
monitoring: false
monitoring: false,
asyncHooks: false
};

if (longStackTraces) Promise.longStackTraces();

return {
asyncHooks: function() {
return config.asyncHooks;
},
longStackTraces: function() {
return config.longStackTraces;
},
Expand Down
8 changes: 3 additions & 5 deletions src/join.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use strict";
module.exports =
function(Promise, PromiseArray, tryConvertToPromise, INTERNAL, async,
getDomain) {
getContext) {
var util = require("./util");
var canEvaluate = util.canEvaluate;
var tryCatch = util.tryCatch;
Expand Down Expand Up @@ -147,10 +147,8 @@ Promise.join = function () {

if (!ret._isFateSealed()) {
if (holder.asyncNeeded) {
var domain = getDomain();
if (domain !== null) {
holder.fn = util.domainBind(domain, holder.fn);
}
var context = getContext();
holder.fn = util.contextBind(context, holder.fn);
}
ret._setAsyncGuaranteed();
ret._setOnCancel(holder);
Expand Down
6 changes: 3 additions & 3 deletions src/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ module.exports = function(Promise,
INTERNAL,
debug) {
var ASSERT = require("./assert");
var getDomain = Promise._getDomain;
var getContext = Promise._getContext;
var util = require("./util");
var tryCatch = util.tryCatch;
var errorObj = util.errorObj;
Expand All @@ -15,8 +15,8 @@ var async = Promise._async;
function MappingPromiseArray(promises, fn, limit, _filter) {
this.constructor$(promises);
this._promise._captureStackTrace();
var domain = getDomain();
this._callback = domain === null ? fn : util.domainBind(domain, fn);
var context = getContext();
this._callback = util.contextBind(context, fn);
this._preservedValues = _filter === INTERNAL
? new Array(this.length())
: null;
Expand Down
59 changes: 35 additions & 24 deletions src/promise.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,32 @@ var UNDEFINED_BINDING = {};
var ASSERT = require("./assert");
var util = require("./util");

var getDomain;
var getContext;
if (util.isNode) {
getDomain = function() {
var ret = process.domain;
if (ret === undefined) ret = null;
return ret;
};
if (util.nodeSupportsAsyncResource) {
var AsyncResource = require("async_hooks").AsyncResource;
getContext = function() {
if (!debug.asyncHooks()) {
return { domain: process.domain };
}
return {
domain: process.domain,
async: new AsyncResource("Bluebird::Promise")
};
};
} else {
getContext = function() {
return {
domain: process.domain
};
};
}
} else {
getDomain = function() {
return null;
getContext = function() {
return {};
};
}
util.notEnumerableProp(Promise, "_getDomain", getDomain);
util.notEnumerableProp(Promise, "_getContext", getContext);

var es5 = require("./es5");
var Async = require("./async");
Expand Down Expand Up @@ -249,7 +262,7 @@ Promise.prototype._then = function (
this._fireEvent("promiseChained", this, promise);
}

var domain = getDomain();
var context = getContext();
if (!BIT_FIELD_CHECK(IS_PENDING_AND_WAITING_NEG)) {
var handler, value, settler = target._settlePromiseCtx;
if (BIT_FIELD_CHECK(IS_FULFILLED)) {
Expand All @@ -267,15 +280,14 @@ Promise.prototype._then = function (
}

async.invoke(settler, target, {
handler: domain === null ? handler
: (typeof handler === "function" &&
util.domainBind(domain, handler)),
handler: util.contextBind(context, handler),
promise: promise,
receiver: receiver,
value: value
});
} else {
target._addCallbacks(didFulfill, didReject, promise, receiver, domain);
target._addCallbacks(didFulfill, didReject, promise,
receiver, context);
}

return promise;
Expand Down Expand Up @@ -401,9 +413,9 @@ Promise.prototype._addCallbacks = function (
reject,
promise,
receiver,
domain
context
) {
ASSERT(typeof domain === "object");
ASSERT(typeof context === "object");
ASSERT(!this._isFateSealed());
ASSERT(!this._isFollowing());
var index = this._length();
Expand All @@ -422,12 +434,10 @@ Promise.prototype._addCallbacks = function (
this._promise0 = promise;
this._receiver0 = receiver;
if (typeof fulfill === "function") {
this._fulfillmentHandler0 =
domain === null ? fulfill : util.domainBind(domain, fulfill);
this._fulfillmentHandler0 = util.contextBind(context, fulfill);
}
if (typeof reject === "function") {
this._rejectionHandler0 =
domain === null ? reject : util.domainBind(domain, reject);
this._rejectionHandler0 = util.contextBind(context, reject);
}
} else {
ASSERT(this[base + CALLBACK_PROMISE_OFFSET] === undefined);
Expand All @@ -439,11 +449,11 @@ Promise.prototype._addCallbacks = function (
this[base + CALLBACK_RECEIVER_OFFSET] = receiver;
if (typeof fulfill === "function") {
this[base + CALLBACK_FULFILL_OFFSET] =
domain === null ? fulfill : util.domainBind(domain, fulfill);
util.contextBind(context, fulfill);
}
if (typeof reject === "function") {
this[base + CALLBACK_REJECT_OFFSET] =
domain === null ? reject : util.domainBind(domain, reject);
util.contextBind(context, reject);
}
}
this._setLength(index + 1);
Expand Down Expand Up @@ -595,7 +605,8 @@ Promise.prototype._settlePromise = function(promise, handler, receiver, value) {
if (tryCatch(handler).call(receiver, value) === errorObj) {
promise._reject(errorObj.e);
}
} else if (handler === reflectHandler) {
} else if (handler === reflectHandler || (handler &&
handler[util.wrappedSymbol] === reflectHandler)) {
promise._fulfill(reflectHandler.call(receiver));
} else if (receiver instanceof Proxyable) {
receiver._promiseCancelled(promise);
Expand Down Expand Up @@ -791,7 +802,7 @@ require("./cancel")(Promise, PromiseArray, apiRejection, debug);
require("./direct_resolve")(Promise);
require("./synchronous_inspection")(Promise);
require("./join")(
Promise, PromiseArray, tryConvertToPromise, INTERNAL, async, getDomain);
Promise, PromiseArray, tryConvertToPromise, INTERNAL, async, getContext);
Promise.Promise = Promise;
Promise.version = "__VERSION__";
};
10 changes: 5 additions & 5 deletions src/reduce.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ module.exports = function(Promise,
tryConvertToPromise,
INTERNAL,
debug) {
var getDomain = Promise._getDomain;
var getContext = Promise._getContext;
var util = require("./util");
var tryCatch = util.tryCatch;

function ReductionPromiseArray(promises, fn, initialValue, _each) {
this.constructor$(promises);
var domain = getDomain();
this._fn = domain === null ? fn : util.domainBind(domain, fn);
var context = getContext();
this._fn = util.contextBind(context, fn);
if (initialValue !== undefined) {
initialValue = Promise.resolve(initialValue);
initialValue._attachCancellationCallback(this);
Expand All @@ -32,8 +32,8 @@ function ReductionPromiseArray(promises, fn, initialValue, _each) {
util.inherits(ReductionPromiseArray, PromiseArray);

ReductionPromiseArray.prototype._gotAccum = function(accum) {
if (this._eachValues !== undefined &&
this._eachValues !== null &&
if (this._eachValues !== undefined &&
this._eachValues !== null &&
accum !== INTERNAL) {
this._eachValues.push(accum);
}
Expand Down
33 changes: 29 additions & 4 deletions src/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -344,8 +344,25 @@ function getNativePromise() {
}
}

function domainBind(self, cb) {
return self.bind(cb);
function contextBind(ctx, cb) {
if (typeof cb !== "function")
return cb;

if (ctx != null && ctx.domain != null) {
cb = ctx.domain.bind(cb);
}

if (ctx != null && ctx.async != null) {
var old = cb;
cb = function() {
INLINE_SLICE(args, arguments);
return ctx.async.runInAsyncScope(function() {
return old.apply(this, args);
}, this);
};
cb[ret.wrappedSymbol] = old;
}
return cb;
}

var ret = {
Expand Down Expand Up @@ -382,17 +399,25 @@ var ret = {
env: env,
global: globalObject,
getNativePromise: getNativePromise,
domainBind: domainBind
contextBind: contextBind
};
ret.isRecentNode = ret.isNode && (function() {
var version;
if (process.versions && process.versions.node) {
if (process.versions && process.versions.node) {
version = process.versions.node.split(".").map(Number);
} else if (process.version) {
version = process.version.split(".").map(Number);
}
return (version[0] === 0 && version[1] > 10) || (version[0] > 0);
})();
ret.nodeSupportsAsyncResource = ret.isNode && (function() {
var version = process.versions.node.split(".").map(Number);
return (version[0] === 9 && version[1] >= 6) || (version[0] > 9);
})();

if (ret.nodeSupportsAsyncResource) {
ret.wrappedSymbol = Symbol();
}

if (ret.isNode) ret.toFastProperties(process);

Expand Down

0 comments on commit e1c4a91

Please sign in to comment.