From a13ff0a56313b23ab45e077ffa941527773d6eed Mon Sep 17 00:00:00 2001 From: Andrey Pechkurov Date: Fri, 5 Jun 2020 11:47:43 +0300 Subject: [PATCH] async_hooks: add bindToAsyncScope method to AsyncResource --- doc/api/async_hooks.md | 32 +++++++++++++++++++ lib/async_hooks.js | 7 ++++ ...der.api.async-resource.bindToAsyncScope.js | 14 ++++++++ 3 files changed, 53 insertions(+) create mode 100644 test/async-hooks/test-embedder.api.async-resource.bindToAsyncScope.js diff --git a/doc/api/async_hooks.md b/doc/api/async_hooks.md index 7d6bd72e7de1fa..b74b1af9117590 100644 --- a/doc/api/async_hooks.md +++ b/doc/api/async_hooks.md @@ -662,6 +662,10 @@ const asyncResource = new AsyncResource( // * restore the original execution context asyncResource.runInAsyncScope(fn, thisArg, ...args); +// Return a wrapper function that always runs in the execution context +// of the resource. +asyncResource.bindToAsyncScope(fn); + // Call AsyncHooks destroy callbacks. asyncResource.emitDestroy(); @@ -723,6 +727,34 @@ of the async resource. This will establish the context, trigger the AsyncHooks before callbacks, call the function, trigger the AsyncHooks after callbacks, and then restore the original execution context. +#### `asyncResource.bindToAsyncScope(fn)` + + +* `fn` {Function} The function to be wrapped. + +Return a wrapper function for the supplied function. The returned funtion, when +it is run, will have the same context as if it was run with +`asyncResource.runInAsyncScope()`. + +The following is a simple demonstration of `asyncResource.bindToAsyncScope()`: + +```js +const { createServer } = require('http'); +const { AsyncResource, executionAsyncId } = require('async_hooks'); + +const server = createServer(function(req, res) { + const asyncResource = new AsyncResource('request'); + const asyncId = asyncResource.asyncId(); + // The listener will always run in the execution context of `asyncResource`. + req.on('close', asyncResource.bindToAsyncScope(() => { + console.log(executionAsyncId()); // Prints the value of `asyncId`. + })); + res.end(); +}).listen(3000); +``` + #### `asyncResource.emitDestroy()` * Returns: {AsyncResource} A reference to `asyncResource`. diff --git a/lib/async_hooks.js b/lib/async_hooks.js index 9e287405f8af0b..24a92198582f2c 100644 --- a/lib/async_hooks.js +++ b/lib/async_hooks.js @@ -196,6 +196,13 @@ class AsyncResource { } } + bindToAsyncScope(fn) { + const self = this; + return function() { + return self.runInAsyncScope(fn, this, ...arguments); + }; + } + emitDestroy() { if (this[destroyedSymbol] !== undefined) { this[destroyedSymbol].destroyed = true; diff --git a/test/async-hooks/test-embedder.api.async-resource.bindToAsyncScope.js b/test/async-hooks/test-embedder.api.async-resource.bindToAsyncScope.js new file mode 100644 index 00000000000000..b0295958e5a873 --- /dev/null +++ b/test/async-hooks/test-embedder.api.async-resource.bindToAsyncScope.js @@ -0,0 +1,14 @@ +'use strict'; +require('../common'); +const assert = require('assert'); +const { AsyncResource, executionAsyncId } = require('async_hooks'); + +const a = new AsyncResource('foobar'); + +function foo(bar) { + assert.strictEqual(executionAsyncId(), a.asyncId()); + return bar; +} + +const ret = a.bindToAsyncScope(foo)('baz'); +assert.strictEqual(ret, 'baz');