contexts[asyncId] = contexts[triggerId];
}
},
// 在销毁对象后会触发 destroy 事件。
destroy: function(asyncId) {
if (!contexts[asyncId]) return;
// 销毁当前异步上下文。
delete contexts[asyncId];
}
});
// 关键!允许该实例中对异步函数启用 hooks 。
hooks.enable();
// 模拟业务处理函数。
function handler(params) {
// 设置 context ,可在中间件中完成此操作(如 Logger Middleware)。
contexts[executionAsyncId()] = params;
// 以下是业务逻辑。
console.log(`handler ${JSON.stringify(params)}`);
f();
}
function f() {
setTimeout(() => {
// 输出所属异步过程的 params 。
console.log(`setTimeout ${JSON.stringify(contexts[executionAsyncId()])}`);
});
}
// 模拟两个异步过程(两个请求)。
setTimeout(handler, 0, { id: 0 });
setTimeout(handler, 0, { id: 1 });
在上述代码中,我们先声明了 contexts 用于存储每个异步过程中的上下文数据(如 Trace ID),随后我们创建了一个 Async Hooks 实例。我们在异步资源初始化时,设置当前 Async ID 对应的上下文数据,使得其数据为调用者的上下文数据;我们在异步资源被销毁时,删除其对应的上下文数据。
通过这种方式,我们只需在一开始设置上下文数据,即可在其引发的各个过程(同步和异步过程)中,获得上下文数据,从而解决了问题。
执行上述代码,其运行结果如下。根据输出日志可知,我们的解决方案是可行的。
handler {"id":0}
handler {"id":1}
setTimeout {"id":0}
setTimeout {"id":1}
不过需要注意的是,Async Hooks 是 实验性 API , 存在一定的性能损耗 ,但 Node 官方正努力将其变得生产可用。因此, 在机器资源足够的情况下,使用本解决方案,牺牲部分性能,换取开发体验。









