You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 02:16:07