在下面的代码中,thing
是一个我无法控制的外部对象;我无法更改 thing
的事件系统的工作方式。当 fn
被调用时,我们返回一个 promise ,其执行者监听一个事件,然后开始等待一系列最终导致该事件被触发的函数:
function fn() {
return new Promise(async function(resolve, reject) {
// This handler must be attached before `c` is called
thing.once('myEvent', function(e) {
resolve(e.data); // done
});
// The order of these functions calls is important,
// and they may produce errors that need to be handled.
await a();
await b();
await c(); // this causes myEvent
});
}
这工作正常,但是 I've been told这是一个 promise 反模式,我应该让 fn
成为一个 async
函数。我该怎么做?如果我将 fn
设为 async
函数,那么我如何从事件处理程序中解析 e.data
?
编辑:
我接受了 Bergi 的回答,因为它有助于解释反模式以及它如何应用于这种情况。话虽如此,我认为上面的代码更具可读性并且明确显示了正在发生的事情,所以我将保持原样。这不是菜鸟谴责最佳实践,只是对于我的用例而言,遵守规则会使事情变得比他们需要的更复杂。当然,这让我对某些人持开放态度 problems ,但在找到更好的方法之前,我只能忍受这一点。
最佳答案
不要在 Promise
构造函数中执行任何 await
ing - 你只应该在那里执行异步回调的 promisification:
async function fn() {
await a();
await b();
await c(); // this causes myEvent
return new Promise(function(resolve, reject) {
thing.once('myEvent', function(e) {
resolve(e.data); // done
});
});
}
启动最终导致事件发出的过程的东西通常也在 Promise
执行器回调中调用(以捕获同步异常),但通常它不会返回 promise 就像您的 c
函数一样。
也许这更好地表达了意图:
async function fn() {
await a();
await b();
const {data} = await new Promise(resolve => {
thing.once('myEvent', resolve);
thing.c(); // this causes myEvent
});
return data;
}
当然,这是假设您只需要在调用其他事件后才开始监听该事件。如果您希望事件在此之前触发,那么您实际上是在进行并行执行竞赛——我建议在这种情况下使用 Promise.all
:
async function fn() {
await a();
await b();
const [{data}, cResult] = await Promise.all([
new Promise(resolve => thing.once('myEvent', resolve)),
c()
]);
return data;
}
如果您的节点 v11.13.0 或更高版本,您可以使用 events.once
method这样您就不必自己构建 promise - 它也能正确处理错误事件:
import { once } from 'events';
async function fn () {
await a()
await b()
await c()
await once(thing, 'myEvent')
}
关于javascript - 使用 promise 等待触发的事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43084557/