async_hooks: add thisArg to AsyncResource.bind

Semver-major

Support setting the `thisArg` for AsyncResource.bind and
AsyncResource.prototype.bind. If `thisArg` is not set,
then `this` will be set to the `AsyncResource` instance.

Fixes: https://github.com/nodejs/node/issues/36051
Signed-off-by: James M Snell <jasnell@gmail.com>

PR-URL: https://github.com/nodejs/node/pull/36782
Reviewed-By: Juan José Arboleda <soyjuanarbol@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Gerhard Stöbich <deb2001-github@yahoo.de>
This commit is contained in:
James M Snell 2021-01-04 10:57:45 -08:00
parent 7dea99b1e6
commit 324a6c235a
No known key found for this signature in database
GPG Key ID: 7341B15C070877AC
3 changed files with 37 additions and 6 deletions

View File

@ -730,30 +730,40 @@ class DBQuery extends AsyncResource {
}
```
#### Static method: `AsyncResource.bind(fn[, type])`
#### Static method: `AsyncResource.bind(fn[, type, [thisArg]])`
<!-- YAML
added:
- v14.8.0
- v12.19.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/36782
description: Added optional thisArg.
-->
* `fn` {Function} The function to bind to the current execution context.
* `type` {string} An optional name to associate with the underlying
`AsyncResource`.
* `thisArg` {any}
Binds the given function to the current execution context.
The returned function will have an `asyncResource` property referencing
the `AsyncResource` to which the function is bound.
#### `asyncResource.bind(fn)`
#### `asyncResource.bind(fn[, thisArg])`
<!-- YAML
added:
- v14.8.0
- v12.19.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/36782
description: Added optional thisArg.
-->
* `fn` {Function} The function to bind to the current `AsyncResource`.
* `thisArg` {any}
Binds the given function to execute to this `AsyncResource`'s scope.

View File

@ -220,10 +220,15 @@ class AsyncResource {
return this[trigger_async_id_symbol];
}
bind(fn) {
bind(fn, thisArg = this) {
if (typeof fn !== 'function')
throw new ERR_INVALID_ARG_TYPE('fn', 'Function', fn);
const ret = FunctionPrototypeBind(this.runInAsyncScope, this, fn);
const ret =
FunctionPrototypeBind(
this.runInAsyncScope,
this,
fn,
thisArg);
ObjectDefineProperties(ret, {
'length': {
configurable: true,
@ -241,9 +246,9 @@ class AsyncResource {
return ret;
}
static bind(fn, type) {
static bind(fn, type, thisArg) {
type = type || fn.name;
return (new AsyncResource(type || 'bound-anonymous-fn')).bind(fn);
return (new AsyncResource(type || 'bound-anonymous-fn')).bind(fn, thisArg);
}
}

View File

@ -33,3 +33,19 @@ setImmediate(() => {
assert.strictEqual(asyncResource.asyncId(), fn2());
assert.notStrictEqual(asyncId, fn2());
});
const foo = {};
const fn3 = asyncResource.bind(common.mustCall(function() {
assert.strictEqual(this, foo);
}), foo);
fn3();
const fn4 = asyncResource.bind(common.mustCall(function() {
assert.strictEqual(this, asyncResource);
}));
fn4();
const fn5 = asyncResource.bind(common.mustCall(function() {
assert.strictEqual(this, false);
}), false);
fn5();