Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'doc/api/async_hooks.md')
-rw-r--r--doc/api/async_hooks.md211
1 files changed, 191 insertions, 20 deletions
diff --git a/doc/api/async_hooks.md b/doc/api/async_hooks.md
index f6805102fdf..e09e89fc377 100644
--- a/doc/api/async_hooks.md
+++ b/doc/api/async_hooks.md
@@ -9,7 +9,11 @@
The `async_hooks` module provides an API to track asynchronous resources. It
can be accessed using:
-```js
+```mjs
+import async_hooks from 'async_hooks';
+```
+
+```cjs
const async_hooks = require('async_hooks');
```
@@ -29,7 +33,55 @@ interface, and each thread will use a new set of async IDs.
Following is a simple overview of the public API.
-```js
+```mjs
+import async_hooks from 'async_hooks';
+
+// Return the ID of the current execution context.
+const eid = async_hooks.executionAsyncId();
+
+// Return the ID of the handle responsible for triggering the callback of the
+// current execution scope to call.
+const tid = async_hooks.triggerAsyncId();
+
+// Create a new AsyncHook instance. All of these callbacks are optional.
+const asyncHook =
+ async_hooks.createHook({ init, before, after, destroy, promiseResolve });
+
+// Allow callbacks of this AsyncHook instance to call. This is not an implicit
+// action after running the constructor, and must be explicitly run to begin
+// executing callbacks.
+asyncHook.enable();
+
+// Disable listening for new asynchronous events.
+asyncHook.disable();
+
+//
+// The following are the callbacks that can be passed to createHook().
+//
+
+// init is called during object construction. The resource may not have
+// completed construction when this callback runs, therefore all fields of the
+// resource referenced by "asyncId" may not have been populated.
+function init(asyncId, type, triggerAsyncId, resource) { }
+
+// Before is called just before the resource's callback is called. It can be
+// called 0-N times for handles (such as TCPWrap), and will be called exactly 1
+// time for requests (such as FSReqCallback).
+function before(asyncId) { }
+
+// After is called just after the resource's callback has finished.
+function after(asyncId) { }
+
+// Destroy is called when the resource is destroyed.
+function destroy(asyncId) { }
+
+// promiseResolve is called only for promise resources, when the
+// `resolve` function passed to the `Promise` constructor is invoked
+// (either directly or through other means of resolving a promise).
+function promiseResolve(asyncId) { }
+```
+
+```cjs
const async_hooks = require('async_hooks');
// Return the ID of the current execution context.
@@ -102,7 +154,16 @@ be tracked, then only the `destroy` callback needs to be passed. The
specifics of all functions that can be passed to `callbacks` is in the
[Hook Callbacks][] section.
-```js
+```mjs
+import { createHook } from 'async_hooks';
+
+const asyncHook = createHook({
+ init(asyncId, type, triggerAsyncId, resource) { },
+ destroy(asyncId) { }
+});
+```
+
+```cjs
const async_hooks = require('async_hooks');
const asyncHook = async_hooks.createHook({
@@ -158,7 +219,17 @@ synchronous logging operation such as `fs.writeFileSync(file, msg, flag)`.
This will print to the file and will not invoke AsyncHooks recursively because
it is synchronous.
-```js
+```mjs
+import { writeFileSync } from 'fs';
+import { format } from 'util';
+
+function debug(...args) {
+ // Use a function like this one when debugging inside an AsyncHooks callback
+ writeFileSync('log.out', `${format(...args)}\n`, { flag: 'a' });
+}
+```
+
+```cjs
const fs = require('fs');
const util = require('util');
@@ -189,7 +260,13 @@ provided, enabling is a no-op.
The `AsyncHook` instance is disabled by default. If the `AsyncHook` instance
should be enabled immediately after creation, the following pattern can be used.
-```js
+```mjs
+import { createHook } from 'async_hooks';
+
+const hook = createHook(callbacks).enable();
+```
+
+```cjs
const async_hooks = require('async_hooks');
const hook = async_hooks.createHook(callbacks).enable();
@@ -229,7 +306,15 @@ This behavior can be observed by doing something like opening a resource then
closing it before the resource can be used. The following snippet demonstrates
this.
-```js
+```mjs
+import { createServer } from 'net';
+
+createServer().listen(function() { this.close(); });
+// OR
+clearTimeout(setTimeout(() => {}, 10));
+```
+
+```cjs
require('net').createServer().listen(function() { this.close(); });
// OR
clearTimeout(setTimeout(() => {}, 10));
@@ -270,12 +355,31 @@ created, while `triggerAsyncId` shows *why* a resource was created.
The following is a simple demonstration of `triggerAsyncId`:
-```js
-const { fd } = process.stdout;
+```mjs
+import { createHook, executionASyncId } from 'async_hooks';
+import { stdout } from 'process';
+import net from 'net';
-async_hooks.createHook({
+createHook({
init(asyncId, type, triggerAsyncId) {
- const eid = async_hooks.executionAsyncId();
+ const eid = executionAsyncId();
+ fs.writeSync(
+ stdout.fd,
+ `${type}(${asyncId}): trigger: ${triggerAsyncId} execution: ${eid}\n`);
+ }
+}).enable();
+
+net.createServer((conn) => {}).listen(8080);
+```
+
+```cjs
+const { createHook, executionAsyncId } = require('async_hooks');
+const { fd } = require('process').stdout;
+const net = require('net');
+
+createHook({
+ init(asyncId, type, triggerAsyncId) {
+ const eid = executionAsyncId();
fs.writeSync(
fd,
`${type}(${asyncId}): trigger: ${triggerAsyncId} execution: ${eid}\n`);
@@ -506,7 +610,17 @@ Using `executionAsyncResource()` in the top-level execution context will
return an empty object as there is no handle or request object to use,
but having an object representing the top-level can be helpful.
-```js
+```mjs
+import { open } from 'fs';
+import { executionAsyncId, executionAsyncResource } from 'async_hooks';
+
+console.log(executionAsyncId(), executionAsyncResource()); // 1 {}
+open(new URL(import.meta.url), 'r', (err, fd) => {
+ console.log(executionAsyncId(), executionAsyncResource()); // 7 FSReqWrap
+});
+```
+
+```cjs
const { open } = require('fs');
const { executionAsyncId, executionAsyncResource } = require('async_hooks');
@@ -519,7 +633,33 @@ open(__filename, 'r', (err, fd) => {
This can be used to implement continuation local storage without the
use of a tracking `Map` to store the metadata:
-```js
+```mjs
+import { createServer } from 'http';
+import {
+ executionAsyncId,
+ executionAsyncResource,
+ createHook
+} from 'async_hooks';
+const sym = Symbol('state'); // Private symbol to avoid pollution
+
+createHook({
+ init(asyncId, type, triggerAsyncId, resource) {
+ const cr = executionAsyncResource();
+ if (cr) {
+ resource[sym] = cr[sym];
+ }
+ }
+}).enable();
+
+const server = createServer((req, res) => {
+ executionAsyncResource()[sym] = { state: req.url };
+ setTimeout(function() {
+ res.end(JSON.stringify(executionAsyncResource()[sym]));
+ }, 100);
+}).listen(3000);
+```
+
+```cjs
const { createServer } = require('http');
const {
executionAsyncId,
@@ -558,7 +698,16 @@ changes:
* Returns: {number} The `asyncId` of the current execution context. Useful to
track when something calls.
-```js
+```mjs
+import { executionAsyncId } from 'async_hooks';
+
+console.log(executionAsyncId()); // 1 - bootstrap
+fs.open(path, 'r', (err, fd) => {
+ console.log(executionAsyncId()); // 6 - open()
+});
+```
+
+```cjs
const async_hooks = require('async_hooks');
console.log(async_hooks.executionAsyncId()); // 1 - bootstrap
@@ -616,10 +765,21 @@ expensive nature of the [promise introspection API][PromiseHooks] provided by
V8. This means that programs using promises or `async`/`await` will not get
correct execution and trigger ids for promise callback contexts by default.
-```js
-const ah = require('async_hooks');
+```mjs
+import { executionAsyncId, triggerAsyncId } from 'async_hooks';
+
+Promise.resolve(1729).then(() => {
+ console.log(`eid ${executionAsyncId()} tid ${triggerAsyncId()}`);
+});
+// produces:
+// eid 1 tid 0
+```
+
+```cjs
+const { executionAsyncId, triggerAsyncId } = require('async_hooks');
+
Promise.resolve(1729).then(() => {
- console.log(`eid ${ah.executionAsyncId()} tid ${ah.triggerAsyncId()}`);
+ console.log(`eid ${executionAsyncId()} tid ${triggerAsyncId()}`);
});
// produces:
// eid 1 tid 0
@@ -633,11 +793,22 @@ the resource that caused (triggered) the `then()` callback to be executed.
Installing async hooks via `async_hooks.createHook` enables promise execution
tracking:
-```js
-const ah = require('async_hooks');
-ah.createHook({ init() {} }).enable(); // forces PromiseHooks to be enabled.
+```mjs
+import { createHook, executionAsyncId, triggerAsyncId } from 'async_hooks';
+createHook({ init() {} }).enable(); // forces PromiseHooks to be enabled.
+Promise.resolve(1729).then(() => {
+ console.log(`eid ${executionAsyncId()} tid ${triggerAsyncId()}`);
+});
+// produces:
+// eid 7 tid 6
+```
+
+```cjs
+const { createHook, exectionAsyncId, triggerAsyncId } = require('async_hooks');
+
+createHook({ init() {} }).enable(); // forces PromiseHooks to be enabled.
Promise.resolve(1729).then(() => {
- console.log(`eid ${ah.executionAsyncId()} tid ${ah.triggerAsyncId()}`);
+ console.log(`eid ${executionAsyncId()} tid ${triggerAsyncId()}`);
});
// produces:
// eid 7 tid 6