为何Node.js中for-await-of遍历EventEmitter后无法执行后续代码?
Node.js异步迭代器导致代码无法执行的问题分析与解决
问题代码
import { on, EventEmitter } from 'node:events'; import process from 'node:process'; const ee = new EventEmitter(); // 稍后触发事件 process.nextTick(() => { ee.emit('foo', 'bar'); ee.emit('foo', 42); }); for await (const event of on(ee, 'foo')) { // 此内部代码块同步执行,一次处理一个事件(即使使用await)。如果需要并发执行请勿使用。 console.log(event); // 打印 ['bar'] [42] } // 无法执行到这里 console.log('Unreachable here');
问题原因
on(ee, 'foo')返回的异步迭代器会持续监听目标事件,不会自动停止。当nextTick里的两次foo事件触发完成后,Node.js事件循环中没有其他待处理任务,但这个迭代器还在等待新的foo事件。而Node.js进程在没有活跃的异步任务(或保持进程的逻辑)时会直接退出,导致循环之后的代码永远没机会运行。
解决方法
要让后续代码执行,必须手动终止异步迭代器的监听,以下是两种实用方案:
方案一:已知事件触发次数时,用Promise.all批量监听
如果明确知道foo事件会触发几次,直接用Promise.all结合once监听所有事件,完成后继续执行后续代码:
import { EventEmitter } from 'node:events'; import process from 'node:process'; const ee = new EventEmitter(); process.nextTick(() => { ee.emit('foo', 'bar'); ee.emit('foo', 42); }); // 监听两次foo事件,全部完成后执行后续逻辑 await Promise.all([ new Promise(resolve => ee.once('foo', resolve)), new Promise(resolve => ee.once('foo', resolve)) ]).then(results => { results.forEach(res => console.log([res])); }); console.log('Unreachable here'); // 现在可以正常打印
方案二:动态终止迭代器(适合事件次数不确定的场景)
如果事件触发次数不固定,可以在最后一次事件发送后,手动终止迭代器:
import { on, EventEmitter } from 'node:events'; import process from 'node:process'; const ee = new EventEmitter(); // 先获取迭代器实例 const eventIterator = on(ee, 'foo'); process.nextTick(() => { ee.emit('foo', 'bar'); ee.emit('foo', 42); // 事件发送完成后,直接终止迭代器 eventIterator.return(); }); for await (const event of eventIterator) { console.log(event); } console.log('Unreachable here'); // 现在可以正常打印
或者用特殊标记值触发循环终止:
import { on, EventEmitter } from 'node:events'; import process from 'node:process'; const ee = new EventEmitter(); process.nextTick(() => { ee.emit('foo', 'bar'); ee.emit('foo', 42); // 发送特殊标记表示事件结束 ee.emit('foo', '__END__'); }); for await (const event of on(ee, 'foo')) { if (event[0] === '__END__') { break; // 跳出循环,执行后续代码 } console.log(event); } console.log('Unreachable here');
内容的提问来源于stack exchange,提问作者Newbie programmer
相关产品推荐
相关产品推荐

