Skip to content

Commit

Permalink
lib: AsyncLocalStorage.bind() and AsyncLocalStorage.snapshot()
Browse files Browse the repository at this point in the history
  • Loading branch information
flakey5 committed Jan 29, 2023
1 parent 19bcba0 commit c8451aa
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 0 deletions.
43 changes: 43 additions & 0 deletions doc/api/async_context.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,49 @@ this time will print the stack trace and exit. See
Creating an async resource within the `onPropagate` callback will result in
a recursive call to `onPropagate`.

### Static method: `AsyncLocalStorage.bind(fn)`

<!-- YAML
added: REPLACEME
-->

* `fn` {Function} The function to bind to the current execution context.

Binds the given function to the current execution context.

The returned function will have an `asyncResource` property referencing
the `AsyncResource` to which the function is bound.

### Static method: `AsyncLocalStorage.snapshot()`

<!-- YAML
added: REPLACEME
-->

Returns a callback that captures the current async context and invokes a
callback passed into it within the captured async context.

```js
const asyncLocalStorage = new AsyncLocalStorage();
const runInAsyncScope = asyncLocalStorage.run(123, () => asyncLocalStorage.snapshot());
const result = asyncLocalStorage.run(321, () => runInAsyncScope(() => asyncLocalStorage.getStore()));
console.log(result); // returns 123
```

AsyncLocalStorage.snapshot() can replace the use of AsyncResource for simple
async context tracking purposes, for example:

```js
class Foo {
#runInAsyncScope = AsyncLocalStorage.snapshot();

get() { return this.#runInAsyncScope(() => asyncLocalStorage.getStore()); }
}

const foo = asyncLocalStorage.run(123, () => new Foo());
console.log(asyncLocalStorage.run(321, () => foo.get())); // returns 123
```

### `asyncLocalStorage.disable()`

<!-- YAML
Expand Down
8 changes: 8 additions & 0 deletions lib/async_hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,14 @@ class AsyncLocalStorage {
this._onPropagate = onPropagate;
}

static bind(fn) {
return new AsyncResource('bound-anonymous-fn').bind(fn);
}

static snapshot() {
return AsyncLocalStorage.bind((cb, ...args) => cb(...args));
}

disable() {
if (this.enabled) {
this.enabled = false;
Expand Down
17 changes: 17 additions & 0 deletions test/parallel/test-async-local-storage-bind.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
'use strict';

const common = require('../common');
const assert = require('assert');
const { AsyncLocalStorage } = require('async_hooks');

[1, false, '', {}, []].forEach((i) => {
assert.throws(() => AsyncLocalStorage.bind(i), {
code: 'ERR_INVALID_ARG_TYPE'
});
});

const fn = common.mustCall(AsyncLocalStorage.bind(() => 123));
assert.strictEqual(fn(), 123);

const fn2 = AsyncLocalStorage.bind(common.mustCall(arg => assert.strictEqual(arg, 'test')));
fn2('test');
10 changes: 10 additions & 0 deletions test/parallel/test-async-local-storage-snapshot.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
'use strict';

require('../common');
const { strictEqual } = require('assert');
const { AsyncLocalStorage } = require('async_hooks');

const asyncLocalStorage = new AsyncLocalStorage();
const runInAsyncScope = asyncLocalStorage.run(123, () => AsyncLocalStorage.snapshot());
const result = asyncLocalStorage.run(321, () => runInAsyncScope(() => asyncLocalStorage.getStore()));
strictEqual(result, 123);

0 comments on commit c8451aa

Please sign in to comment.