Is there a version of setTimeout that returns an ES6 promise?

后端 未结 3 1507
天涯浪人
天涯浪人 2020-12-14 14:59

Similar to this question, but rather than asking about how promises work in general, I specifically want to know:

What is the standard/best way to wrap setTimeout in

相关标签:
3条回答
  • 2020-12-14 15:30

    Here's how I'd implement it:

    function delay(duration, func) {
      var args = Array.prototype.slice.call(arguments, 2);
    
      return new Promise(function (resolve) {
        setTimeout(function () {
          resolve(func.apply(null, args));
        }, duration);
      });
    }
    

    (ES5-syntax intentionally chosen)

    But maybe there's a common library that already does this, or a better way to do it.

    0 讨论(0)
  • 2020-12-14 15:40

    In Browsers

    First of all no - there is no built in for this. Lots of libraries that enhance ES2015 promises like bluebird whip with it.

    I think the other answer conflates executing the function and a delay, it also creates timeouts that are impossible to cancel. I'd write it simply as:

    function delay(ms){
        var ctr, rej, p = new Promise(function (resolve, reject) {
            ctr = setTimeout(resolve, ms);
            rej = reject;
        });
        p.cancel = function(){ clearTimeout(ctr); rej(Error("Cancelled"))};
        return p; 
    }
    

    Then you can do:

    delay(1000).then(/* ... do whatever */);
    

    Or

     doSomething().then(function(){ return delay(1000); }).then(doSomethingElse);
    

    If we only want the basic functionality in ES2015, it's even simpler as:

    let delay = ms => new Promise(r => setTimeout(r, ms));
    

    In Node

    You can use util.promisify on setTimeout to get a delay function back - meaning you don't have to use the new Promise constructor anymore.

    0 讨论(0)
  • 2020-12-14 15:46

    If you need the proper cancellation of promised timeout similar to clearTimeout - returning the promise directly from setTimeout is not convenient. Especially when using with ES7 async / await in try...finally block. It is better to have separate variable for timeout manipulation. I've implemented this approach as tiny await-timeout package. It works as following:

    import Timeout from 'await-timeout';
    
    async function foo() {
      const timeout = new Timeout();
      try {
        const fetchPromise = fetch('https://example.com');
        const timerPromise = timeout.set(1000).then(() => console.log('Timeout!'));
        await Promise.race([fetchPromise, timerPromise]);
      } finally {
        timeout.clear();
      }
    }
    

    In this example timeout will definitely be cleared in case of fetch success or any error and console.log('Timeout!') will not be called.

    0 讨论(0)
提交回复
热议问题