最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Resolving a promise after some time t or if an event fires, whichever occurs first - Stack Overflow

programmeradmin0浏览0评论

I have a function called wait which accepts time in milliseconds and returns a promise. The promise should get resolved if myEvent is fired or after some time ms whichever occurs first. Currently I am doing something like this which I don't think is the right way to do it.

async function wait(ms) {
    return new Promise((res) => {
        myEmitter.on('myEvent', res);
        setTimeout(res, ms);
    });
}

Is there a better way to do this?

I have a function called wait which accepts time in milliseconds and returns a promise. The promise should get resolved if myEvent is fired or after some time ms whichever occurs first. Currently I am doing something like this which I don't think is the right way to do it.

async function wait(ms) {
    return new Promise((res) => {
        myEmitter.on('myEvent', res);
        setTimeout(res, ms);
    });
}

Is there a better way to do this?

Share Improve this question asked Jan 25, 2021 at 8:11 Aditya DSAditya DS 1032 silver badges9 bronze badges 2
  • 2 Wouldn't the caller like to know the difference between the event and the timeout? – jfriend00 Commented Jan 25, 2021 at 8:18
  • @jfriend00 Not necessary for my use case – Aditya DS Commented Jan 25, 2021 at 8:56
Add a ment  | 

2 Answers 2

Reset to default 4

What you're doing is fine.¹ Once the promise is settled (by the first call to the resolve function or reject function, to use their usual names), calling the resolve/reject functions again doesn't do anything at all. So what you have is the simple way to write it.

If you were doing something with a side effect like res(doSomethingAndReturnValue()) in the event handler or timeout handler, that wouldn't be a good idea because the doSomethingAndReturnValue() part still executes and has its side effects. But in your example you aren't doing that.


¹ Three fairly minor notes:

  1. I assume that when your event handler is called, some information is passed to the handler. Since you're using res directly as the handler, it will receive that information. So you have it set up to fulfill the promise with the value the event handler gets (if the event fires first), or with undefined (if the timer fires first), which means the code using it sees varying fulfillment values.

  2. Typically I'd expect a timeout to be a rejection rather than a fulfillment, but it depends on your use case.

  3. Your function doesn't need the async modifier, because it never uses await. A function doesn't need async just because it returns a promise. As of a normative change to the spec a year or so back, it no longer makes a difference if you return a native promise from an async function as you're doing (it used to delay things very briefly), but there's no reason for it.

Your code is correct. A promise can only be resolved once - if you resolve it twice, the second one is effectively a no-op.

With that said, as an alternative you can use Promise.race which has the same idea. It takes promises as input and will produce a promise that settles when the first of the input of promises settles.

For example, clicking the button here settles a promise but it also gets settled in 10 seconds:

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>

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论