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

能否异步等待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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 19:22:47