在一段时间后或事件触发后解析承诺,以先发生者为准



我有一个名为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()部分仍然执行并具有其副作用。但在你的例子中,你没有这样做。


¹三个相当小的音符:

  1. 我假设当您的事件处理程序被调用时,一些信息被传递给处理程序。由于您直接使用res作为处理程序,因此它将接收该信息。因此,您可以将其设置为使用事件处理程序获得的值(如果事件首先触发)或undefined(如果计时器首先触发)来履行承诺,这意味着使用它的代码看到不同的履行值。

  2. 通常我希望超时是拒绝而不是完成,但这取决于您的用例。

  3. 你的函数不需要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>

最新更新