Skip to content

Commit c1651be

Browse files
flakey5targos
authored andcommitted
lib: add AsyncLocalStorage.bind() and .snapshot()
PR-URL: #46387 Reviewed-By: Stephen Belanger <admin@stephenbelanger.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Gerhard Stöbich <deb2001-github@yahoo.de>
1 parent 617b5b1 commit c1651be

File tree

4 files changed

+91
-0
lines changed

4 files changed

+91
-0
lines changed

doc/api/async_context.md

Lines changed: 50 additions & 0 deletions
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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,14 @@ class AsyncLocalStorage {
279279
this.enabled = false;
280280
}
281281

282+
static bind(fn) {
283+
return AsyncResource.bind(fn);
284+
}
285+
286+
static snapshot() {
287+
return AsyncLocalStorage.bind((cb, ...args) => cb(...args));
288+
}
289+
282290
disable() {
283291
if (this.enabled) {
284292
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: 16 additions & 0 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy