Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 45d2f4d

Browse filesBrowse files
jasnelladdaleax
authored andcommitted
async_hooks: add AsyncResource.bind utility
Creates an internal AsyncResource and binds a function to it, ensuring that the function is invoked within execution context in which bind was called. PR-URL: #34574 Reviewed-By: Stephen Belanger <admin@stephenbelanger.com> Reviewed-By: Gus Caplan <me@gus.host> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Andrey Pechkurov <apechkurov@gmail.com> Reviewed-By: Gerhard Stöbich <deb2001-github@yahoo.de>
1 parent e7486d4 commit 45d2f4d
Copy full SHA for 45d2f4d

File tree

Expand file treeCollapse file tree

3 files changed

+90
-5
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

3 files changed

+90
-5
lines changed
Open diff view settings
Collapse file

‎doc/api/async_hooks.md‎

Copy file name to clipboardExpand all lines: doc/api/async_hooks.md
+31-5Lines changed: 31 additions & 5 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,32 @@ class DBQuery extends AsyncResource {
733733
}
734734
```
735735

736+
#### `static AsyncResource.bind(fn[, type])`
737+
<!-- YAML
738+
added: REPLACEME
739+
-->
740+
741+
* `fn` {Function} The function to bind to the current execution context.
742+
* `type` {string} An optional name to associate with the underlying
743+
`AsyncResource`.
744+
745+
Binds the given function to the current execution context.
746+
747+
The returned function will have an `asyncResource` property referencing
748+
the `AsyncResource` to which the function is bound.
749+
750+
#### `asyncResource.bind(fn)`
751+
<!-- YAML
752+
added: REPLACEME
753+
-->
754+
755+
* `fn` {Function} The function to bind to the current `AsyncResource`.
756+
757+
Binds the given function to execute to this `AsyncResource`'s scope.
758+
759+
The returned function will have an `asyncResource` property referencing
760+
the `AsyncResource` to which the function is bound.
761+
736762
#### `asyncResource.runInAsyncScope(fn[, thisArg, ...args])`
737763
<!-- YAML
738764
added: v9.6.0
@@ -904,12 +930,12 @@ const { createServer } = require('http');
904930
const { AsyncResource, executionAsyncId } = require('async_hooks');
905931

906932
const server = createServer((req, res) => {
907-
const asyncResource = new AsyncResource('request');
908-
// The listener will always run in the execution context of `asyncResource`.
909-
req.on('close', asyncResource.runInAsyncScope.bind(asyncResource, () => {
910-
// Prints: true
911-
console.log(asyncResource.asyncId() === executionAsyncId());
933+
req.on('close', AsyncResource.bind(() => {
934+
// Execution context is bound to the current outer scope.
912935
}));
936+
req.on('close', () => {
937+
// Execution context is bound to the scope that caused 'close' to emit.
938+
});
913939
res.end();
914940
}).listen(3000);
915941
```
Collapse file

‎lib/async_hooks.js‎

Copy file name to clipboardExpand all lines: lib/async_hooks.js
+24Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22

33
const {
44
NumberIsSafeInteger,
5+
ObjectDefineProperties,
56
ReflectApply,
67
Symbol,
78
} = primordials;
89

910
const {
1011
ERR_ASYNC_CALLBACK,
1112
ERR_ASYNC_TYPE,
13+
ERR_INVALID_ARG_TYPE,
1214
ERR_INVALID_ASYNC_ID
1315
} = require('internal/errors').codes;
1416
const { validateString } = require('internal/validators');
@@ -208,6 +210,28 @@ class AsyncResource {
208210
triggerAsyncId() {
209211
return this[trigger_async_id_symbol];
210212
}
213+
214+
bind(fn) {
215+
if (typeof fn !== 'function')
216+
throw new ERR_INVALID_ARG_TYPE('fn', 'Function', fn);
217+
const ret = this.runInAsyncScope.bind(this, fn);
218+
ObjectDefineProperties(ret, {
219+
'length': {
220+
enumerable: true,
221+
value: fn.length,
222+
},
223+
'asyncResource': {
224+
enumerable: true,
225+
value: this,
226+
}
227+
});
228+
return ret;
229+
}
230+
231+
static bind(fn, type) {
232+
type = type || fn.name;
233+
return (new AsyncResource(type || 'bound-anonymous-fn')).bind(fn);
234+
}
211235
}
212236

213237
const storageList = [];
Collapse file
+35Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const assert = require('assert');
5+
const { AsyncResource, executionAsyncId } = require('async_hooks');
6+
7+
const fn = common.mustCall(AsyncResource.bind(() => {
8+
return executionAsyncId();
9+
}));
10+
11+
setImmediate(() => {
12+
const asyncId = executionAsyncId();
13+
assert.notStrictEqual(asyncId, fn());
14+
});
15+
16+
const asyncResource = new AsyncResource('test');
17+
18+
[1, false, '', {}, []].forEach((i) => {
19+
assert.throws(() => asyncResource.bind(i), {
20+
code: 'ERR_INVALID_ARG_TYPE'
21+
});
22+
});
23+
24+
const fn2 = asyncResource.bind((a, b) => {
25+
return executionAsyncId();
26+
});
27+
28+
assert.strictEqual(fn2.asyncResource, asyncResource);
29+
assert.strictEqual(fn2.length, 2);
30+
31+
setImmediate(() => {
32+
const asyncId = executionAsyncId();
33+
assert.strictEqual(asyncResource.asyncId(), fn2());
34+
assert.notStrictEqual(asyncId, fn2());
35+
});

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.