Node.js v26.0.0 文档
- Node.js v26.0.0
- 目录
- 异步上下文跟踪
- 介绍
- 类:
AsyncLocalStoragenew AsyncLocalStorage([options])- 静态方法:
AsyncLocalStorage.bind(fn) - 静态方法:
AsyncLocalStorage.snapshot() asyncLocalStorage.disable()asyncLocalStorage.getStore()asyncLocalStorage.enterWith(store)asyncLocalStorage.nameasyncLocalStorage.run(store, callback[, ...args])asyncLocalStorage.exit(callback[, ...args])asyncLocalStorage.withScope(store)- 与
async/await一起使用 - 故障排除:上下文丢失
- 类:
RunScope - 类:
AsyncResourcenew AsyncResource(type[, options])- 静态方法:
AsyncResource.bind(fn[, type[, thisArg]]) asyncResource.bind(fn[, thisArg])asyncResource.runInAsyncScope(fn[, thisArg, ...args])asyncResource.emitDestroy()asyncResource.asyncId()asyncResource.triggerAsyncId()- 为
Worker线程池使用AsyncResource - 将
AsyncResource与EventEmitter集成
- 异步上下文跟踪
- 索引
- 关于本文档
- 用法与示例
- 断言测试
- 异步上下文跟踪
- 异步钩子
- 缓冲区
- C++ 插件
- 使用 Node-API 的 C/C++ 插件
- C++ 嵌入器 API
- 子进程
- 集群
- 命令行选项
- 控制台
- 加密
- 调试器
- 已弃用的 API
- 诊断通道
- DNS
- 域
- 环境变量
- 错误
- 事件
- 文件系统
- 全局对象
- HTTP
- HTTP/2
- HTTPS
- 检查器
- 国际化
- 模块:CommonJS 模块
- 模块:ECMAScript 模块
- 模块:
node:moduleAPI - 模块:包
- 模块:TypeScript
- 网络
- 可迭代流 API
- 操作系统
- 路径
- 性能钩子
- 权限
- 进程
- Punycode
- 查询字符串
- 逐行读取
- REPL
- 报告
- 单一可执行文件应用
- SQLite
- 流
- 字符串解码器
- 测试运行器
- 定时器
- TLS/SSL
- 跟踪事件
- TTY
- UDP/数据报
- URL
- 实用工具
- V8
- 虚拟机
- WASI
- Web Crypto API
- Web Streams API
- 工作线程
- Zlib
- Zlib 可迭代压缩
- 其他版本
- 选项
异步上下文跟踪#
稳定性:2 - 稳定
简介#
这些类用于关联状态并在回调和 Promise 链中传播它。它们允许在 Web 请求或任何其他异步持续时间期间存储数据。这类似于其他语言中的线程局部存储(Thread-local storage)。
AsyncLocalStorage 和 AsyncResource 类是 node:async_hooks 模块的一部分。
import { AsyncLocalStorage, AsyncResource } from 'node:async_hooks';const { AsyncLocalStorage, AsyncResource } = require('node:async_hooks');
类:AsyncLocalStorage#
此类创建在异步操作中保持连贯的存储。
虽然你可以在 node:async_hooks 模块之上创建自己的实现,但应优先使用 AsyncLocalStorage,因为它是一个高性能且内存安全的实现,其中包含大量非显而易见的优化。
以下示例使用 AsyncLocalStorage 构建了一个简单的日志记录器,它为传入的 HTTP 请求分配 ID,并将它们包含在每个请求内记录的消息中。
import http from 'node:http'; import { AsyncLocalStorage } from 'node:async_hooks'; const asyncLocalStorage = new AsyncLocalStorage(); function logWithId(msg) { const id = asyncLocalStorage.getStore(); console.log(`${id !== undefined ? id : '-'}:`, msg); } let idSeq = 0; http.createServer((req, res) => { asyncLocalStorage.run(idSeq++, () => { logWithId('start'); // Imagine any chain of async operations here setImmediate(() => { logWithId('finish'); res.end(); }); }); }).listen(8080); http.get('https://:8080'); http.get('https://:8080'); // Prints: // 0: start // 0: finish // 1: start // 1: finishconst http = require('node:http'); const { AsyncLocalStorage } = require('node:async_hooks'); const asyncLocalStorage = new AsyncLocalStorage(); function logWithId(msg) { const id = asyncLocalStorage.getStore(); console.log(`${id !== undefined ? id : '-'}:`, msg); } let idSeq = 0; http.createServer((req, res) => { asyncLocalStorage.run(idSeq++, () => { logWithId('start'); // Imagine any chain of async operations here setImmediate(() => { logWithId('finish'); res.end(); }); }); }).listen(8080); http.get('https://:8080'); http.get('https://:8080'); // Prints: // 0: start // 0: finish // 1: start // 1: finish
AsyncLocalStorage 的每个实例都维护一个独立的存储上下文。多个实例可以同时安全存在,而不会相互干扰数据。
new AsyncLocalStorage([options])#
创建 AsyncLocalStorage 的新实例。存储仅在 run() 调用内或 enterWith() 调用后提供。
静态方法:AsyncLocalStorage.bind(fn)#
fn<Function>要绑定到当前执行上下文的函数。- 返回:
<Function>一个新函数,它在捕获的执行上下文中调用fn。
将给定函数绑定到当前执行上下文。
静态方法:AsyncLocalStorage.snapshot()#
- 返回:
<Function>一个具有签名(fn: (...args) : R, ...args) : R的新函数。
捕获当前执行上下文并返回一个接受函数作为参数的函数。每当调用返回的函数时,它都会在捕获的上下文中调用传递给它的函数。
const asyncLocalStorage = new AsyncLocalStorage();
const runInAsyncScope = asyncLocalStorage.run(123, () => AsyncLocalStorage.snapshot());
const result = asyncLocalStorage.run(321, () => runInAsyncScope(() => asyncLocalStorage.getStore()));
console.log(result); // returns 123
AsyncLocalStorage.snapshot() 可以替代 AsyncResource 用于简单的异步上下文跟踪目的,例如
class Foo {
#runInAsyncScope = AsyncLocalStorage.snapshot();
get() { return this.#runInAsyncScope(() => asyncLocalStorage.getStore()); }
}
const foo = asyncLocalStorage.run(123, () => new Foo());
console.log(asyncLocalStorage.run(321, () => foo.get())); // returns 123
asyncLocalStorage.disable()#
稳定性:1 - 实验性
禁用 AsyncLocalStorage 实例。所有后续对 asyncLocalStorage.getStore() 的调用都将返回 undefined,直到再次调用 asyncLocalStorage.run() 或 asyncLocalStorage.enterWith() 为止。
调用 asyncLocalStorage.disable() 时,所有链接到该实例的当前上下文都将退出。
在 asyncLocalStorage 被垃圾回收之前,需要调用 asyncLocalStorage.disable()。这不适用于 asyncLocalStorage 提供的存储,因为这些对象会随相应的异步资源一起被垃圾回收。
当当前进程中不再使用 asyncLocalStorage 时,请使用此方法。
asyncLocalStorage.getStore()#
- 返回:
<any>
返回当前存储。如果是在通过调用 asyncLocalStorage.run() 或 asyncLocalStorage.enterWith() 初始化的异步上下文之外调用,则返回 undefined。
asyncLocalStorage.enterWith(store)#
稳定性:1 - 实验性
store<any>
在当前同步执行的剩余部分进入上下文,并随后在任何后续异步调用中持久保留该存储。
示例
const store = { id: 1 };
// Replaces previous store with the given store object
asyncLocalStorage.enterWith(store);
asyncLocalStorage.getStore(); // Returns the store object
someAsyncOperation(() => {
asyncLocalStorage.getStore(); // Returns the same object
});
此转换将持续整个同步执行过程。这意味着,例如,如果在事件处理程序内进入了上下文,后续的事件处理程序也会在该上下文中运行,除非通过 AsyncResource 特别绑定到另一个上下文。这就是为什么应该优先使用 run() 而不是 enterWith(),除非有充分的理由使用后者。
const store = { id: 1 };
emitter.on('my-event', () => {
asyncLocalStorage.enterWith(store);
});
emitter.on('my-event', () => {
asyncLocalStorage.getStore(); // Returns the same object
});
asyncLocalStorage.getStore(); // Returns undefined
emitter.emit('my-event');
asyncLocalStorage.getStore(); // Returns the same object
asyncLocalStorage.name#
- 类型:
<string>
如果提供了名称,则为 AsyncLocalStorage 实例的名称。
asyncLocalStorage.run(store, callback[, ...args])#
store<any>callback<Function>...args<any>
在一个上下文中同步运行一个函数并返回其返回值。存储在回调函数之外不可访问。存储对回调内创建的任何异步操作均可访问。
可选的 args 被传递给回调函数。
如果回调函数抛出错误,该错误也会由 run() 抛出。堆栈跟踪不受此调用的影响,上下文也会退出。
示例
const store = { id: 2 };
try {
asyncLocalStorage.run(store, () => {
asyncLocalStorage.getStore(); // Returns the store object
setTimeout(() => {
asyncLocalStorage.getStore(); // Returns the store object
}, 200);
throw new Error();
});
} catch (e) {
asyncLocalStorage.getStore(); // Returns undefined
// The error will be caught here
}
asyncLocalStorage.exit(callback[, ...args])#
稳定性:1 - 实验性
callback<Function>...args<any>
在上下文之外同步运行一个函数并返回其返回值。存储在回调函数内或回调内创建的异步操作中不可访问。在回调函数内进行的任何 getStore() 调用都将始终返回 undefined。
可选的 args 被传递给回调函数。
如果回调函数抛出错误,该错误也会由 exit() 抛出。堆栈跟踪不受此调用的影响,上下文也会重新进入。
示例
// Within a call to run
try {
asyncLocalStorage.getStore(); // Returns the store object or value
asyncLocalStorage.exit(() => {
asyncLocalStorage.getStore(); // Returns undefined
throw new Error();
});
} catch (e) {
asyncLocalStorage.getStore(); // Returns the same object or value
// The error will be caught here
}
asyncLocalStorage.withScope(store)#
稳定性:1 - 实验性
store<any>- 返回:{RunScope}
创建一个可清理(disposable)的作用域,进入给定的存储,并在作用域被清理时自动恢复之前的存储值。此方法旨在与 JavaScript 的显式资源管理(using 语法)配合使用。
示例
import { AsyncLocalStorage } from 'node:async_hooks'; const asyncLocalStorage = new AsyncLocalStorage(); { using _ = asyncLocalStorage.withScope('my-store'); console.log(asyncLocalStorage.getStore()); // Prints: my-store } console.log(asyncLocalStorage.getStore()); // Prints: undefinedconst { AsyncLocalStorage } = require('node:async_hooks'); const asyncLocalStorage = new AsyncLocalStorage(); { using _ = asyncLocalStorage.withScope('my-store'); console.log(asyncLocalStorage.getStore()); // Prints: my-store } console.log(asyncLocalStorage.getStore()); // Prints: undefined
withScope() 方法对于管理同步代码中的上下文特别有用,你希望在退出代码块时确保恢复之前的存储值,即使发生了错误也是如此。
import { AsyncLocalStorage } from 'node:async_hooks'; const asyncLocalStorage = new AsyncLocalStorage(); try { using _ = asyncLocalStorage.withScope('my-store'); console.log(asyncLocalStorage.getStore()); // Prints: my-store throw new Error('test'); } catch (e) { // Store is automatically restored even after error console.log(asyncLocalStorage.getStore()); // Prints: undefined }const { AsyncLocalStorage } = require('node:async_hooks'); const asyncLocalStorage = new AsyncLocalStorage(); try { using _ = asyncLocalStorage.withScope('my-store'); console.log(asyncLocalStorage.getStore()); // Prints: my-store throw new Error('test'); } catch (e) { // Store is automatically restored even after error console.log(asyncLocalStorage.getStore()); // Prints: undefined }
重要:在 async 函数的第一个 await 之前使用 withScope() 时,请注意作用域更改会影响调用者的上下文。async 函数的同步部分(第一个 await 之前)在被调用时立即运行,当它到达第一个 await 时,它会将 Promise 返回给调用者。此时,作用域更改在调用者的上下文中变为可见,并将持续存在于随后的同步代码中,直到其他因素更改了作用域值。对于异步操作,请优先使用 run(),它能正确隔离跨异步边界的上下文。
import { AsyncLocalStorage } from 'node:async_hooks';
const asyncLocalStorage = new AsyncLocalStorage();
async function example() {
using _ = asyncLocalStorage.withScope('my-store');
console.log(asyncLocalStorage.getStore()); // Prints: my-store
await someAsyncOperation(); // Function pauses here and returns promise
console.log(asyncLocalStorage.getStore()); // Prints: my-store
}
// Calling without await
example(); // Synchronous portion runs, then pauses at first await
// After the promise is returned, the scope 'my-store' is now active in caller!
console.log(asyncLocalStorage.getStore()); // Prints: my-store (unexpected!)
与 async/await 一起使用#
如果在一个 async 函数内,只有一个 await 调用需要在上下文中运行,则应使用以下模式
async function fn() {
await asyncLocalStorage.run(new Map(), () => {
asyncLocalStorage.getStore().set('key', value);
return foo(); // The return value of foo will be awaited
});
}
在此示例中,存储仅在回调函数和由 foo 调用的函数中可用。在 run 之外,调用 getStore 将返回 undefined。
故障排除:上下文丢失#
在大多数情况下,AsyncLocalStorage 工作正常。在极少数情况下,当前存储会在异步操作之一中丢失。
如果你的代码是基于回调的,使用 util.promisify() 将其转换为 Promise 即可,这样它就可以使用原生 Promise 工作。
如果你需要使用基于回调的 API,或者你的代码假定了自定义的 thenable 实现,请使用 AsyncResource 类将异步操作与正确的执行上下文关联起来。通过在怀疑导致丢失的调用之后记录 asyncLocalStorage.getStore() 的内容,找出导致上下文丢失的函数调用。当代码记录 undefined 时,最后调用的回调很可能是导致上下文丢失的原因。
类:RunScope#
稳定性:1 - 实验性
由 asyncLocalStorage.withScope() 返回的可清理作用域,在被清理时会自动恢复之前的存储值。此类实现了 显式资源管理 协议,旨在与 JavaScript 的 using 语法配合使用。
当 using 代码块退出时(无论是通过正常完成还是抛出错误),该作用域都会自动恢复之前的存储值。
scope.dispose()#
显式结束作用域并恢复之前的存储值。此方法是幂等的:多次调用它与调用一次具有相同的效果。
[Symbol.dispose]() 方法会委托给 dispose()。
如果调用 withScope() 时没有使用 using 关键字,则必须手动调用 dispose() 以恢复之前的存储值。忘记调用 dispose() 会导致存储值在当前执行上下文的剩余部分中持续存在。
import { AsyncLocalStorage } from 'node:async_hooks'; const storage = new AsyncLocalStorage(); // Without using, the scope must be disposed manually const scope = storage.withScope('my-store'); // storage.getStore() === 'my-store' here scope.dispose(); // Restore previous value // storage.getStore() === undefined hereconst { AsyncLocalStorage } = require('node:async_hooks'); const storage = new AsyncLocalStorage(); // Without using, the scope must be disposed manually const scope = storage.withScope('my-store'); // storage.getStore() === 'my-store' here scope.dispose(); // Restore previous value // storage.getStore() === undefined here
类:AsyncResource#
AsyncResource 类旨在由嵌入者的异步资源进行扩展。使用它,用户可以轻松触发其自身资源的生命周期事件。
当实例化 AsyncResource 时,将触发 init 钩子。
以下是 AsyncResource API 的概述。
import { AsyncResource, executionAsyncId } from 'node:async_hooks'; // AsyncResource() is meant to be extended. Instantiating a // new AsyncResource() also triggers init. If triggerAsyncId is omitted then // async_hook.executionAsyncId() is used. const asyncResource = new AsyncResource( type, { triggerAsyncId: executionAsyncId(), requireManualDestroy: false }, ); // Run a function in the execution context of the resource. This will // * establish the context of the resource // * trigger the AsyncHooks before callbacks // * call the provided function `fn` with the supplied arguments // * trigger the AsyncHooks after callbacks // * restore the original execution context asyncResource.runInAsyncScope(fn, thisArg, ...args); // Call AsyncHooks destroy callbacks. asyncResource.emitDestroy(); // Return the unique ID assigned to the AsyncResource instance. asyncResource.asyncId(); // Return the trigger ID for the AsyncResource instance. asyncResource.triggerAsyncId();const { AsyncResource, executionAsyncId } = require('node:async_hooks'); // AsyncResource() is meant to be extended. Instantiating a // new AsyncResource() also triggers init. If triggerAsyncId is omitted then // async_hook.executionAsyncId() is used. const asyncResource = new AsyncResource( type, { triggerAsyncId: executionAsyncId(), requireManualDestroy: false }, ); // Run a function in the execution context of the resource. This will // * establish the context of the resource // * trigger the AsyncHooks before callbacks // * call the provided function `fn` with the supplied arguments // * trigger the AsyncHooks after callbacks // * restore the original execution context asyncResource.runInAsyncScope(fn, thisArg, ...args); // Call AsyncHooks destroy callbacks. asyncResource.emitDestroy(); // Return the unique ID assigned to the AsyncResource instance. asyncResource.asyncId(); // Return the trigger ID for the AsyncResource instance. asyncResource.triggerAsyncId();
new AsyncResource(type[, options])#
用法示例:
class DBQuery extends AsyncResource {
constructor(db) {
super('DBQuery');
this.db = db;
}
getInfo(query, callback) {
this.db.get(query, (err, data) => {
this.runInAsyncScope(callback, null, err, data);
});
}
close() {
this.db = null;
this.emitDestroy();
}
}
静态方法:AsyncResource.bind(fn[, type[, thisArg]])#
fn<Function>要绑定到当前执行上下文的函数。type<string>可选的名称,用于与底层的AsyncResource关联。thisArg<any>
将给定函数绑定到当前执行上下文。
asyncResource.bind(fn[, thisArg])#
fn<Function>要绑定到当前AsyncResource的函数。thisArg<any>
将给定的函数绑定到此 AsyncResource 的作用域中执行。
asyncResource.runInAsyncScope(fn[, thisArg, ...args])#
fn<Function>要在此异步资源的执行上下文中调用的函数。thisArg<any>函数调用中要使用的接收者(receiver)。...args<any>要传递给函数的可选参数。
在异步资源的执行上下文中,使用提供的参数调用所提供的函数。这将建立上下文,触发 AsyncHooks 前置回调,调用函数,触发 AsyncHooks 后置回调,然后恢复原始的执行上下文。
asyncResource.emitDestroy()#
- 返回:
<AsyncResource>对asyncResource的引用。
调用所有 destroy 钩子。此方法应仅被调用一次。如果调用超过一次,将抛出错误。此方法必须手动调用。如果资源留给 GC 进行回收,则 destroy 钩子将永远不会被调用。
asyncResource.asyncId()#
- 返回:
<number>分配给资源的唯一asyncId。
asyncResource.triggerAsyncId()#
- 返回:
<number>传递给AsyncResource构造函数的同一个triggerAsyncId。
为 Worker 线程池使用 AsyncResource#
以下示例展示了如何使用 AsyncResource 类为 Worker 池正确提供异步跟踪。其他资源池(例如数据库连接池)可以遵循类似的模式。
假设任务是相加两个数字,使用名为 task_processor.js 且包含以下内容的文件
import { parentPort } from 'node:worker_threads'; parentPort.on('message', (task) => { parentPort.postMessage(task.a + task.b); });const { parentPort } = require('node:worker_threads'); parentPort.on('message', (task) => { parentPort.postMessage(task.a + task.b); });
围绕它的 Worker 池可以使用以下结构
import { AsyncResource } from 'node:async_hooks'; import { EventEmitter } from 'node:events'; import { Worker } from 'node:worker_threads'; const kTaskInfo = Symbol('kTaskInfo'); const kWorkerFreedEvent = Symbol('kWorkerFreedEvent'); class WorkerPoolTaskInfo extends AsyncResource { constructor(callback) { super('WorkerPoolTaskInfo'); this.callback = callback; } done(err, result) { this.runInAsyncScope(this.callback, null, err, result); this.emitDestroy(); // `TaskInfo`s are used only once. } } export default class WorkerPool extends EventEmitter { constructor(numThreads) { super(); this.numThreads = numThreads; this.workers = []; this.freeWorkers = []; this.tasks = []; for (let i = 0; i < numThreads; i++) this.addNewWorker(); // Any time the kWorkerFreedEvent is emitted, dispatch // the next task pending in the queue, if any. this.on(kWorkerFreedEvent, () => { if (this.tasks.length > 0) { const { task, callback } = this.tasks.shift(); this.runTask(task, callback); } }); } addNewWorker() { const worker = new Worker(new URL('task_processor.js', import.meta.url)); worker.on('message', (result) => { // In case of success: Call the callback that was passed to `runTask`, // remove the `TaskInfo` associated with the Worker, and mark it as free // again. worker[kTaskInfo].done(null, result); worker[kTaskInfo] = null; this.freeWorkers.push(worker); this.emit(kWorkerFreedEvent); }); worker.on('error', (err) => { // In case of an uncaught exception: Call the callback that was passed to // `runTask` with the error. if (worker[kTaskInfo]) worker[kTaskInfo].done(err, null); else this.emit('error', err); // Remove the worker from the list and start a new Worker to replace the // current one. this.workers.splice(this.workers.indexOf(worker), 1); this.addNewWorker(); }); this.workers.push(worker); this.freeWorkers.push(worker); this.emit(kWorkerFreedEvent); } runTask(task, callback) { if (this.freeWorkers.length === 0) { // No free threads, wait until a worker thread becomes free. this.tasks.push({ task, callback }); return; } const worker = this.freeWorkers.pop(); worker[kTaskInfo] = new WorkerPoolTaskInfo(callback); worker.postMessage(task); } close() { for (const worker of this.workers) worker.terminate(); } }const { AsyncResource } = require('node:async_hooks'); const { EventEmitter } = require('node:events'); const path = require('node:path'); const { Worker } = require('node:worker_threads'); const kTaskInfo = Symbol('kTaskInfo'); const kWorkerFreedEvent = Symbol('kWorkerFreedEvent'); class WorkerPoolTaskInfo extends AsyncResource { constructor(callback) { super('WorkerPoolTaskInfo'); this.callback = callback; } done(err, result) { this.runInAsyncScope(this.callback, null, err, result); this.emitDestroy(); // `TaskInfo`s are used only once. } } class WorkerPool extends EventEmitter { constructor(numThreads) { super(); this.numThreads = numThreads; this.workers = []; this.freeWorkers = []; this.tasks = []; for (let i = 0; i < numThreads; i++) this.addNewWorker(); // Any time the kWorkerFreedEvent is emitted, dispatch // the next task pending in the queue, if any. this.on(kWorkerFreedEvent, () => { if (this.tasks.length > 0) { const { task, callback } = this.tasks.shift(); this.runTask(task, callback); } }); } addNewWorker() { const worker = new Worker(path.resolve(__dirname, 'task_processor.js')); worker.on('message', (result) => { // In case of success: Call the callback that was passed to `runTask`, // remove the `TaskInfo` associated with the Worker, and mark it as free // again. worker[kTaskInfo].done(null, result); worker[kTaskInfo] = null; this.freeWorkers.push(worker); this.emit(kWorkerFreedEvent); }); worker.on('error', (err) => { // In case of an uncaught exception: Call the callback that was passed to // `runTask` with the error. if (worker[kTaskInfo]) worker[kTaskInfo].done(err, null); else this.emit('error', err); // Remove the worker from the list and start a new Worker to replace the // current one. this.workers.splice(this.workers.indexOf(worker), 1); this.addNewWorker(); }); this.workers.push(worker); this.freeWorkers.push(worker); this.emit(kWorkerFreedEvent); } runTask(task, callback) { if (this.freeWorkers.length === 0) { // No free threads, wait until a worker thread becomes free. this.tasks.push({ task, callback }); return; } const worker = this.freeWorkers.pop(); worker[kTaskInfo] = new WorkerPoolTaskInfo(callback); worker.postMessage(task); } close() { for (const worker of this.workers) worker.terminate(); } } module.exports = WorkerPool;
如果没有 WorkerPoolTaskInfo 对象添加的显式跟踪,回调似乎与各个 Worker 对象相关联。但是,Worker 的创建与任务的创建无关,并且不提供关于任务何时被调度的信息。
此池的使用方式如下
import WorkerPool from './worker_pool.js'; import os from 'node:os'; const pool = new WorkerPool(os.availableParallelism()); let finished = 0; for (let i = 0; i < 10; i++) { pool.runTask({ a: 42, b: 100 }, (err, result) => { console.log(i, err, result); if (++finished === 10) pool.close(); }); }const WorkerPool = require('./worker_pool.js'); const os = require('node:os'); const pool = new WorkerPool(os.availableParallelism()); let finished = 0; for (let i = 0; i < 10; i++) { pool.runTask({ a: 42, b: 100 }, (err, result) => { console.log(i, err, result); if (++finished === 10) pool.close(); }); }
将 AsyncResource 与 EventEmitter 集成#
由 EventEmitter 触发的事件监听器可能在与调用 eventEmitter.on() 时激活的执行上下文不同的上下文中运行。
以下示例展示了如何使用 AsyncResource 类将事件监听器正确关联到正确的执行上下文。同样的方法可以应用于 Stream 或类似的事件驱动类。
import { createServer } from 'node:http'; import { AsyncResource, executionAsyncId } from 'node:async_hooks'; const server = createServer((req, res) => { req.on('close', AsyncResource.bind(() => { // Execution context is bound to the current outer scope. })); req.on('close', () => { // Execution context is bound to the scope that caused 'close' to emit. }); res.end(); }).listen(3000);const { createServer } = require('node:http'); const { AsyncResource, executionAsyncId } = require('node:async_hooks'); const server = createServer((req, res) => { req.on('close', AsyncResource.bind(() => { // Execution context is bound to the current outer scope. })); req.on('close', () => { // Execution context is bound to the scope that caused 'close' to emit. }); res.end(); }).listen(3000);