异步上下文示例
¥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()
回调的 'parent' 的原因。
¥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)