异步上下文示例
【Asynchronous context example】
上下文跟踪用例由稳定的 API AsyncLocalStorage 覆盖。这个例子仅说明异步钩子的操作,但 AsyncLocalStorage 更适合这个用例。
【The context tracking use case is covered by the stable API AsyncLocalStorage.
This example only illustrates async hooks operation but AsyncLocalStorage
fits better to this use case.】
以下是一个示例,提供了有关在 before 和 after 调用之间对 init 的调用的附加信息,特别是 listen() 的回调将是什么样子。输出格式稍微复杂一些,以便更容易看到调用上下文。
【The following is an example with additional information about the calls to
init between the before and after calls, specifically what the
callback to listen() will look like. The output formatting is slightly more
elaborate to make calling context easier to see.】
import async_hooks from 'node:async_hooks';
import fs from 'node:fs';
import net from 'node:net';
import { stdout } from 'node:process';
const { fd } = stdout;
let indent = 0;
async_hooks.createHook({
init(asyncId, type, triggerAsyncId) {
const eid = async_hooks.executionAsyncId();
const indentStr = ' '.repeat(indent);
fs.writeSync(
fd,
`${indentStr}${type}(${asyncId}):` +
` trigger: ${triggerAsyncId} execution: ${eid}\n`);
},
before(asyncId) {
const indentStr = ' '.repeat(indent);
fs.writeSync(fd, `${indentStr}before: ${asyncId}\n`);
indent += 2;
},
after(asyncId) {
indent -= 2;
const indentStr = ' '.repeat(indent);
fs.writeSync(fd, `${indentStr}after: ${asyncId}\n`);
},
destroy(asyncId) {
const indentStr = ' '.repeat(indent);
fs.writeSync(fd, `${indentStr}destroy: ${asyncId}\n`);
},
}).enable();
net.createServer(() => {}).listen(8080, () => {
// Let's wait 10ms before logging the server started.
setTimeout(() => {
console.log('>>>', async_hooks.executionAsyncId());
}, 10);
});const async_hooks = require('node:async_hooks');
const fs = require('node:fs');
const net = require('node:net');
const { fd } = process.stdout;
let indent = 0;
async_hooks.createHook({
init(asyncId, type, triggerAsyncId) {
const eid = async_hooks.executionAsyncId();
const indentStr = ' '.repeat(indent);
fs.writeSync(
fd,
`${indentStr}${type}(${asyncId}):` +
` trigger: ${triggerAsyncId} execution: ${eid}\n`);
},
before(asyncId) {
const indentStr = ' '.repeat(indent);
fs.writeSync(fd, `${indentStr}before: ${asyncId}\n`);
indent += 2;
},
after(asyncId) {
indent -= 2;
const indentStr = ' '.repeat(indent);
fs.writeSync(fd, `${indentStr}after: ${asyncId}\n`);
},
destroy(asyncId) {
const indentStr = ' '.repeat(indent);
fs.writeSync(fd, `${indentStr}destroy: ${asyncId}\n`);
},
}).enable();
net.createServer(() => {}).listen(8080, () => {
// Let's wait 10ms before logging the server started.
setTimeout(() => {
console.log('>>>', async_hooks.executionAsyncId());
}, 10);
});仅启动服务器的输出:
【Output from only starting the server:】
TCPSERVERWRAP(5): trigger: 1 execution: 1
TickObject(6): trigger: 5 execution: 1
before: 6
Timeout(7): trigger: 6 execution: 6
after: 6
destroy: 6
before: 7
>>> 7
TickObject(8): trigger: 7 execution: 7
after: 7
before: 8
after: 8 如示例所示,executionAsyncId() 和 execution 各自指定当前执行上下文的值;该上下文由对 before 和 after 的调用来划定。
【As illustrated in the example, executionAsyncId() and execution each specify
the value of the current execution context; which is delineated by calls to
before and after.】
仅使用 execution 来绘制资源分配会产生以下结果:
【Only using execution to graph resource allocation results in the following:】
root(1)
^
|
TickObject(6)
^
|
Timeout(7) TCPSERVERWRAP 并不是这个图的一部分,尽管它是 console.log() 被调用的原因。这是因为绑定到一个没有主机名的端口是一个同步操作,但为了保持完全异步的 API,用户的回调被放在 process.nextTick() 中。这就是为什么输出中会出现 TickObject,并且它是 .listen() 回调的“父级”。
【The TCPSERVERWRAP is not part of this graph, even though it was the reason for
console.log() being called. This is because binding to a port without a host
name is a synchronous operation, but to maintain a completely asynchronous
API the user's callback is placed in a process.nextTick(). Which is why
TickObject is present in the output and is a 'parent' for .listen()
callback.】
该图仅显示资源的创建时间,而不显示原因,因此要追踪原因,请使用 triggerAsyncId。其可以用以下图表示:
【The graph only shows when a resource was created, not why, so to track
the why use triggerAsyncId. Which can be represented with the following
graph:】
bootstrap(1)
|
˅
TCPSERVERWRAP(5)
|
˅
TickObject(6)
|
˅
Timeout(7)