如何从async函数中正确返回PromiEvent?
如何从async函数正确返回PromiEvent?
这个问题的核心在于async函数的特性:async函数会自动将任何返回值(哪怕是已经是Promise的对象)包装成一个全新的Promise实例。而你用new Web3PromiEvent()创建的实例,虽然本身继承了Promise,但同时附加了on等事件相关方法——当async函数返回它时,这些附加方法会被外层的包装Promise覆盖,导致你拿到的只是一个普通Promise,自然找不到on处理器。
解决方法:放弃用async声明inner函数
既然async函数会强制包装返回值,那我们改用普通函数来编写inner逻辑,用.then()处理异步操作,这样就能直接返回原始的PromiEvent实例,保留它的事件监听能力:
const Web3PromiEvent = require('web3-core-promievent') function sleep() { return new Promise((resolve) => setTimeout(resolve, 1000)) } // 改用普通函数,不用async function inner() { const pe = new Web3PromiEvent() sleep().then(() => { pe.eventEmitter.emit('done', 'ok') pe.resolve('ok') }) return pe } async function main() { const pe = inner() pe.on('done', console.log) const res = await pe console.log(res) } main()
为什么这个方法有效?
普通函数不会对返回值做额外包装,所以你拿到的pe就是原始的PromiEvent实例——它既是一个可以await的Promise,同时拥有on方法来监听事件,完美契合你的需求。
如果一定要用async函数怎么办?
如果业务逻辑必须用async/await,那你需要手动把PromiEvent的事件方法挂载到async函数返回的Promise上。不过这种方式比较hack,不推荐,因为会破坏Promise的原生结构:
async function inner() { const pe = new Web3PromiEvent() await sleep() pe.eventEmitter.emit('done', 'ok') pe.resolve('ok') // 把PromiEvent的on方法绑定到async返回的Promise上 const promise = pe promise.on = (...args) => pe.eventEmitter.on(...args) return promise }
但还是更推荐第一种方案,保持代码的简洁性和语义正确性。
内容的提问来源于stack exchange,提问作者Dmitriy
相关产品推荐
相关产品推荐

