我有一个名为wait
的函数,它接受以毫秒为单位的时间并返回一个承诺。如果myEvent
被触发,或者在ms
被触发一段时间后,以先发生的为准,该承诺将得到解决。目前我正在做这样的事情,我认为这不是正确的方法。
async function wait(ms) {
return new Promise((res) => {
myEmitter.on('myEvent', res);
setTimeout(res, ms);
});
}
有更好的方法吗?
你做的很好。¹一旦承诺被解决(通过第一次调用resolve
函数或reject
函数,使用它们的常用名称),再次调用resolve
/reject
函数根本不做任何事情。所以你有一个简单的方法来写它。
如果您在事件处理程序或超时处理程序中执行具有res(doSomethingAndReturnValue())
副作用的操作,那么将不是一个好主意,因为doSomethingAndReturnValue()
部分仍然执行并具有其副作用。但在你的例子中,你没有这样做。
¹三个相当小的音符:
-
我假设当您的事件处理程序被调用时,一些信息被传递给处理程序。由于您直接使用
res
作为处理程序,因此它将接收该信息。因此,您可以将其设置为使用事件处理程序获得的值(如果事件首先触发)或undefined
(如果计时器首先触发)来履行承诺,这意味着使用它的代码看到不同的履行值。 -
通常我希望超时是拒绝而不是完成,但这取决于您的用例。
-
你的函数不需要
async
修饰符,因为它从不使用await
。一个函数不需要async
只是因为它返回一个承诺。由于大约一年前规范的变化,如果你从async
函数返回原生承诺,它不再有什么区别(它曾经延迟事情very)。简短),但没有理由。
代码是正确的。一个承诺只能被解决一次——如果你解决了两次,那么第二次承诺实际上是无操作的。
话虽如此,作为替代方案,您可以使用具有相同想法的Promise.race
。它接受承诺作为输入,并在第一个承诺输入结束时生成一个承诺。
例如,点击这里的按钮确定一个承诺,但它也会在10秒内完成:
let buttonResolve;
let buttonPromise = new Promise(res => buttonResolve = res);
document.querySelector("button")
.addEventListener("click", buttonResolve)
let timedPromise = new Promise(res => setTimeout(res, 10000));
let start = Date.now();
Promise.race([buttonPromise, timedPromise])
.then(() => console.log(`finished in ${(Date.now() - start) / 1000}s`))
<button>Click me</button>