Skip to content

Commit c8451aa

Browse files
committed
lib: AsyncLocalStorage.bind() and AsyncLocalStorage.snapshot()
1 parent 19bcba0 commit c8451aa

File tree

4 files changed

+78
-0
lines changed

4 files changed

+78
-0
lines changed

doc/api/async_context.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,49 @@ this time will print the stack trace and exit. See
147147
Creating an async resource within the `onPropagate` callback will result in
148148
a recursive call to `onPropagate`.
149149

150+
### Static method: `AsyncLocalStorage.bind(fn)`
151+
152+
<!-- YAML
153+
added: REPLACEME
154+
-->
155+
156+
* `fn` {Function} The function to bind to the current execution context.
157+
158+
Binds the given function to the current execution context.
159+
160+
The returned function will have an `asyncResource` property referencing
161+
the `AsyncResource` to which the function is bound.
162+
163+
### Static method: `AsyncLocalStorage.snapshot()`
164+
165+
<!-- YAML
166+
added: REPLACEME
167+
-->
168+
169+
Returns a callback that captures the current async context and invokes a
170+
callback passed into it within the captured async context.
171+
172+
```js
173+
const asyncLocalStorage = new AsyncLocalStorage();
174+
const runInAsyncScope = asyncLocalStorage.run(123, () => asyncLocalStorage.snapshot());
175+
const result = asyncLocalStorage.run(321, () => runInAsyncScope(() => asyncLocalStorage.getStore()));
176+
console.log(result); // returns 123
177+
```
178+
179+
AsyncLocalStorage.snapshot() can replace the use of AsyncResource for simple
180+
async context tracking purposes, for example:
181+
182+
```js
183+
class Foo {
184+
#runInAsyncScope = AsyncLocalStorage.snapshot();
185+
186+
get() { return this.#runInAsyncScope(() => asyncLocalStorage.getStore()); }
187+
}
188+
189+
const foo = asyncLocalStorage.run(123, () => new Foo());
190+
console.log(asyncLocalStorage.run(321, () => foo.get())); // returns 123
191+
```
192+
150193
### `asyncLocalStorage.disable()`
151194

152195
<!-- YAML

lib/async_hooks.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,14 @@ class AsyncLocalStorage {
288288
this._onPropagate = onPropagate;
289289
}
290290

291+
static bind(fn) {
292+
return new AsyncResource('bound-anonymous-fn').bind(fn);
293+
}
294+
295+
static snapshot() {
296+
return AsyncLocalStorage.bind((cb, ...args) => cb(...args));
297+
}
298+
291299
disable() {
292300
if (this.enabled) {
293301
this.enabled = false;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const assert = require('assert');
5+
const { AsyncLocalStorage } = require('async_hooks');
6+
7+
[1, false, '', {}, []].forEach((i) => {
8+
assert.throws(() => AsyncLocalStorage.bind(i), {
9+
code: 'ERR_INVALID_ARG_TYPE'
10+
});
11+
});
12+
13+
const fn = common.mustCall(AsyncLocalStorage.bind(() => 123));
14+
assert.strictEqual(fn(), 123);
15+
16+
const fn2 = AsyncLocalStorage.bind(common.mustCall(arg => assert.strictEqual(arg, 'test')));
17+
fn2('test');
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
'use strict';
2+
3+
require('../common');
4+
const { strictEqual } = require('assert');
5+
const { AsyncLocalStorage } = require('async_hooks');
6+
7+
const asyncLocalStorage = new AsyncLocalStorage();
8+
const runInAsyncScope = asyncLocalStorage.run(123, () => AsyncLocalStorage.snapshot());
9+
const result = asyncLocalStorage.run(321, () => runInAsyncScope(() => asyncLocalStorage.getStore()));
10+
strictEqual(result, 123);

0 commit comments

Comments
 (0)