能否异步等待Node.js EventEmitter的event.on()完成后再执行后续代码?
如何在Node.js中异步等待EventEmitter事件完成数据填充?
是否可以在执行函数剩余代码前,异步等待Node.js EventEmitter的event.on()完成数据填充?
原问题示例代码
import { EventEmitter } from 'node:events' let bus = new EventEmitter() async function demo(){ let foo const listen = async function (channelName, callback){ await bus.on(channelName, data => { callback(data) }) } await listen('test', data => { foo = data }) // 手动添加延迟可以解决此问题 // while (foo == undefined){ await new Promise(resolve => setTimeout(resolve, 1000)) } // 但不添加延迟时会返回'undefined' console.log(foo) } demo()
问题原因
原代码的核心问题是:bus.on()是同步注册事件监听器的方法,它不会返回Promise,所以await bus.on()完全没有异步等待的效果——代码会直接跳过await执行后续逻辑,此时test事件还未触发,foo自然还是undefined。手动加延迟只是临时规避,并非合理的异步处理方案。
正确解决方案
将事件监听逻辑包装成Promise,利用Promise的特性让await等待事件触发后再继续执行。推荐使用event.once()(避免重复监听同一事件)实现:
import { EventEmitter } from 'node:events' let bus = new EventEmitter() async function demo(){ // 封装等待事件的工具函数 const waitForEvent = (emitter, eventName) => { return new Promise(resolve => { emitter.once(eventName, resolve); }); } // 异步等待'test'事件触发,直接获取数据 const foo = await waitForEvent(bus, 'test'); console.log(foo); // 此时foo已被事件填充数据 } demo() // 模拟业务中触发事件的逻辑(实际场景可能由其他模块触发) setTimeout(() => { bus.emit('test', '来自事件的填充数据'); }, 1500);
方案说明
waitForEvent返回一个Promise,当once监听到目标事件时,会调用resolve并传递事件数据;await会暂停当前函数执行,直到Promise被resolve,确保后续代码执行时foo已有值;- 使用
once而非on,是因为我们只需要等待事件触发一次,避免注册无用的重复监听器。
内容的提问来源于stack exchange,提问作者respectabiggle
相关产品推荐
相关产品推荐

