summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/api/async_hooks.md42
-rw-r--r--lib/async_hooks.js6
-rw-r--r--test/async-hooks/test-async-local-storage-enter-with.js20
3 files changed, 65 insertions, 3 deletions
diff --git a/doc/api/async_hooks.md b/doc/api/async_hooks.md
index 5990291716..f02d3ff755 100644
--- a/doc/api/async_hooks.md
+++ b/doc/api/async_hooks.md
@@ -950,6 +950,48 @@ If this method is called outside of an asynchronous context initialized by
calling `asyncLocalStorage.run` or `asyncLocalStorage.runAndReturn`, it will
return `undefined`.
+### `asyncLocalStorage.enterWith(store)`
+<!-- YAML
+added: REPLACEME
+-->
+
+* `store` {any}
+
+Calling `asyncLocalStorage.enterWith(store)` will transition into the context
+for the remainder of the current synchronous execution and will persist
+through any following asynchronous calls.
+
+Example:
+
+```js
+const store = { id: 1 };
+asyncLocalStorage.enterWith(store);
+asyncLocalStorage.getStore(); // Returns the store object
+someAsyncOperation(() => {
+ asyncLocalStorage.getStore(); // Returns the same object
+});
+```
+
+This transition will continue for the _entire_ synchronous execution.
+This means that if, for example, the context is entered within an event
+handler subsequent event handlers will also run within that context unless
+specifically bound to another context with an `AsyncResource`.
+
+```js
+const store = { id: 1 };
+
+emitter.on('my-event', () => {
+ asyncLocalStorage.enterWith(store);
+});
+emitter.on('my-event', () => {
+ asyncLocalStorage.getStore(); // Returns the same object
+});
+
+asyncLocalStorage.getStore(); // Returns undefined
+emitter.emit('my-event');
+asyncLocalStorage.getStore(); // Returns the same object
+```
+
### `asyncLocalStorage.run(store, callback[, ...args])`
<!-- YAML
added: v13.10.0
diff --git a/lib/async_hooks.js b/lib/async_hooks.js
index bd3cd57d02..d676f6dfcb 100644
--- a/lib/async_hooks.js
+++ b/lib/async_hooks.js
@@ -245,7 +245,7 @@ class AsyncLocalStorage {
}
}
- _enter(store) {
+ enterWith(store) {
if (!this.enabled) {
this.enabled = true;
storageList.push(this);
@@ -258,7 +258,7 @@ class AsyncLocalStorage {
runSyncAndReturn(store, callback, ...args) {
const resource = executionAsyncResource();
const outerStore = resource[this.kResourceStore];
- this._enter(store);
+ this.enterWith(store);
try {
return callback(...args);
} finally {
@@ -288,7 +288,7 @@ class AsyncLocalStorage {
run(store, callback, ...args) {
const resource = executionAsyncResource();
const outerStore = resource[this.kResourceStore];
- this._enter(store);
+ this.enterWith(store);
process.nextTick(callback, ...args);
resource[this.kResourceStore] = outerStore;
}
diff --git a/test/async-hooks/test-async-local-storage-enter-with.js b/test/async-hooks/test-async-local-storage-enter-with.js
new file mode 100644
index 0000000000..736dd83f85
--- /dev/null
+++ b/test/async-hooks/test-async-local-storage-enter-with.js
@@ -0,0 +1,20 @@
+'use strict';
+require('../common');
+const assert = require('assert');
+const { AsyncLocalStorage } = require('async_hooks');
+
+const asyncLocalStorage = new AsyncLocalStorage();
+
+setImmediate(() => {
+ const store = { foo: 'bar' };
+ asyncLocalStorage.enterWith(store);
+
+ assert.strictEqual(asyncLocalStorage.getStore(), store);
+ setTimeout(() => {
+ assert.strictEqual(asyncLocalStorage.getStore(), store);
+ }, 10);
+});
+
+setTimeout(() => {
+ assert.strictEqual(asyncLocalStorage.getStore(), undefined);
+}, 10);