Promise 执行跟踪


【Promise execution tracking】

默认情况下,promise 执行不会被分配 asyncId,因为 V8 提供的 承诺内省 API 相对开销较大。这意味着使用 promise 或 async/await 的程序默认情况下不会获得正确的执行和触发 id 对于 promise 回调上下文。

【By default, promise executions are not assigned asyncIds due to the relatively expensive nature of the promise introspection API 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.】

import { executionAsyncId, triggerAsyncId } from 'node:async_hooks';

Promise.resolve(1729).then(() => {
  console.log(`eid ${executionAsyncId()} tid ${triggerAsyncId()}`);
});
// produces:
// eid 1 tid 0const { executionAsyncId, triggerAsyncId } = require('node:async_hooks');

Promise.resolve(1729).then(() => {
  console.log(`eid ${executionAsyncId()} tid ${triggerAsyncId()}`);
});
// produces:
// eid 1 tid 0

请注意,then() 回调声称是在外部作用域的上下文中执行的,即使其中涉及异步跳转。此外,triggerAsyncId 的值为 0,这意味着我们缺少关于导致(触发)then() 回调执行的资源的上下文信息。

【Observe that the then() callback claims to have executed in the context of the outer scope even though there was an asynchronous hop involved. Also, the triggerAsyncId value is 0, which means that we are missing context about the resource that caused (triggered) the then() callback to be executed.】

通过 async_hooks.createHook 安装异步钩子可以启用对 Promise 执行的跟踪:

【Installing async hooks via async_hooks.createHook enables promise execution tracking:】

import { createHook, executionAsyncId, triggerAsyncId } from 'node:async_hooks';
createHook({ init() {} }).enable(); // forces PromiseHooks to be enabled.
Promise.resolve(1729).then(() => {
  console.log(`eid ${executionAsyncId()} tid ${triggerAsyncId()}`);
});
// produces:
// eid 7 tid 6const { createHook, executionAsyncId, triggerAsyncId } = require('node: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

在这个例子中,添加任何实际的钩子函数都可以启用对 Promise 的跟踪。上面的例子中有两个 Promise:一个是由 Promise.resolve() 创建的 Promise,另一个是 then() 调用返回的 Promise。在上面的例子中,第一个 Promise 得到了 asyncId 6,后一个得到了 asyncId 7。在执行 then() 回调期间,我们是在 asyncId7 的 Promise 上下文中执行的。这个 Promise 是由异步资源 6 触发的。

【In this example, adding any actual hook function enabled the tracking of promises. There are two promises in the example above; the promise created by Promise.resolve() and the promise returned by the call to then(). In the example above, the first promise got the asyncId 6 and the latter got asyncId 7. During the execution of the then() callback, we are executing in the context of promise with asyncId 7. This promise was triggered by async resource 6.】

关于 Promise 的另一个微妙之处是,beforeafter 回调只会在链式 Promise 上运行。这意味着不是通过 then()/catch() 创建的 Promise 不会触发其 beforeafter 回调。更多详细信息请参阅 V8 Promise钩子 API 的相关说明。

【Another subtlety with promises is that before and after callbacks are run only on chained promises. That means promises not created by then()/catch() will not have the before and after callbacks fired on them. For more details see the details of the V8 PromiseHooks API.】