Skip to content

Commit 8842c99

Browse files
committed
lib: add AsyncLocalStorage.bind() and .snapshot()
1 parent 85f9b27 commit 8842c99

4 files changed

+91
-0
lines changed

doc/api/async_context.md

+50
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,56 @@ changes:
136136
Creates a new instance of `AsyncLocalStorage`. Store is only provided within a
137137
`run()` call or after an `enterWith()` call.
138138

139+
### Static method: `AsyncLocalStorage.bind(fn)`
140+
141+
<!-- YAML
142+
added: REPLACEME
143+
-->
144+
145+
> Stability: 1 - Experimental
146+
147+
* `fn` {Function} The function to bind to the current execution context.
148+
* Returns: {Function} A new function that calls `fn` within the captured
149+
execution context.
150+
151+
Binds the given function to the current execution context.
152+
153+
### Static method: `AsyncLocalStorage.snapshot()`
154+
155+
<!-- YAML
156+
added: REPLACEME
157+
-->
158+
159+
> Stability: 1 - Experimental
160+
161+
* Returns: {Function} A new function with the signature
162+
`(fn: (...args) : R, ...args) : R`.
163+
164+
Captures the current execution context and returns a function that accepts a
165+
function as an argument. Whenever the returned function is called, it
166+
calls the function passed to it within the captured context.
167+
168+
```js
169+
const asyncLocalStorage = new AsyncLocalStorage();
170+
const runInAsyncScope = asyncLocalStorage.run(123, () => asyncLocalStorage.snapshot());
171+
const result = asyncLocalStorage.run(321, () => runInAsyncScope(() => asyncLocalStorage.getStore()));
172+
console.log(result); // returns 123
173+
```
174+
175+
AsyncLocalStorage.snapshot() can replace the use of AsyncResource for simple
176+
async context tracking purposes, for example:
177+
178+
```js
179+
class Foo {
180+
#runInAsyncScope = AsyncLocalStorage.snapshot();
181+
182+
get() { return this.#runInAsyncScope(() => asyncLocalStorage.getStore()); }
183+
}
184+
185+
const foo = asyncLocalStorage.run(123, () => new Foo());
186+
console.log(asyncLocalStorage.run(321, () => foo.get())); // returns 123
187+
```
188+
139189
### `asyncLocalStorage.disable()`
140190

141191
<!-- YAML

lib/async_hooks.js

+8
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,14 @@ class AsyncLocalStorage {
287287
this.enabled = false;
288288
}
289289

290+
static bind(fn) {
291+
return AsyncResource.bind(fn);
292+
}
293+
294+
static snapshot() {
295+
return AsyncLocalStorage.bind((cb, ...args) => cb(...args));
296+
}
297+
290298
disable() {
291299
if (this.enabled) {
292300
this.enabled = false;
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');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const { strictEqual } = require('assert');
5+
const { AsyncLocalStorage } = require('async_hooks');
6+
7+
const asyncLocalStorage = new AsyncLocalStorage();
8+
const runInAsyncScope =
9+
asyncLocalStorage.run(123, common.mustCall(() => AsyncLocalStorage.snapshot()));
10+
const result =
11+
asyncLocalStorage.run(321, common.mustCall(() => {
12+
return runInAsyncScope(() => {
13+
return asyncLocalStorage.getStore();
14+
});
15+
}));
16+
strictEqual(result, 123);

0 commit comments

Comments
 (0)