Skip to content

Commit 6c6bdf8

Browse files
committed
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.
1 parent ca26eae commit 6c6bdf8

3 files changed

Lines changed: 60 additions & 5 deletions

File tree

doc/api/async_hooks.md

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,26 @@ class DBQuery extends AsyncResource {
729729
}
730730
```
731731

732+
#### `static AsyncResource.bind(fn[, type])`
733+
<!-- YAML
734+
added: REPLACEME
735+
-->
736+
737+
* `fn` {Function} The function to bind to the current execution context.
738+
* `type` {string} An optional name to associate with the underlying
739+
`AsyncResource`.
740+
741+
Binds the given function to the current execution context.
742+
743+
#### `asyncResource.bind(fn)`
744+
<!-- YAML
745+
added: REPLACEME
746+
-->
747+
748+
* `fn` {Function} The function to bind to the current `AsyncResource`.
749+
750+
Binds the given function to execute to this `AsyncResource`'s scope.
751+
732752
#### `asyncResource.runInAsyncScope(fn[, thisArg, ...args])`
733753
<!-- YAML
734754
added: v9.6.0
@@ -900,12 +920,12 @@ const { createServer } = require('http');
900920
const { AsyncResource, executionAsyncId } = require('async_hooks');
901921

902922
const server = createServer((req, res) => {
903-
const asyncResource = new AsyncResource('request');
904-
// The listener will always run in the execution context of `asyncResource`.
905-
req.on('close', asyncResource.runInAsyncScope.bind(asyncResource, () => {
906-
// Prints: true
907-
console.log(asyncResource.asyncId() === executionAsyncId());
923+
req.on('close', AsyncResource.bind(() => {
924+
// Execution context is bound to the current outer scope.
908925
}));
926+
req.on('close', () => {
927+
// Execution context is bound to the scope that caused 'close' to emit.
928+
});
909929
res.end();
910930
}).listen(3000);
911931
```

lib/async_hooks.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,15 @@ class AsyncResource {
211211
triggerAsyncId() {
212212
return this[trigger_async_id_symbol];
213213
}
214+
215+
bind(fn) {
216+
return this.runInAsyncScope.bind(this, fn);
217+
}
218+
219+
static bind(fn, type) {
220+
type = type || fn.name;
221+
return (new AsyncResource(type || 'bound-anonymous-fn')).bind(fn);
222+
}
214223
}
215224

216225
const storageList = [];
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
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+
const fn2 = asyncResource.bind(() => {
19+
return executionAsyncId();
20+
});
21+
22+
setImmediate(() => {
23+
const asyncId = executionAsyncId();
24+
assert.strictEqual(asyncResource.asyncId(), fn2());
25+
assert.notStrictEqual(asyncId, fn2());
26+
});

0 commit comments

Comments
 (0)