Promise 执行跟踪


默认情况下,由于 V8 提供的 promise 自省 API 相对昂贵,因此不会为 promise 执行分配 asyncId。 这意味着默认情况下,使用 promise 或 async/await 的程序将无法正确执行并触发 promise 回调上下文的 id。

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

注意 then() 回调声称已在外部范围的上下文中执行,即使涉及异步的跃点。 另外,triggerAsyncId 的值是 0,这意味着我们缺少有关导致(触发)then() 回调被执行的资源的上下文。

通过 async_hooks.createHook 安装异步钩子启用 promise 执行跟踪:

const ah = require('async_hooks');
ah.createHook({ init() {} }).enable(); // 强制启用 PromiseHooks。
Promise.resolve(1729).then(() => {
  console.log(`eid ${ah.executionAsyncId()} tid ${ah.triggerAsyncId()}`);
});
// 产生:
// eid 7 tid 6

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

promise 的另一个微妙之处是 beforeafter 回调仅在链式 promise 上运行。 这意味着不是由 then()/catch() 创建的 promise 不会触发 beforeafter 回调。 更多详细信息请参见 V8 PromiseHooks API 的详细信息。