Understanding promise.race() usage

后端 未结 6 1487
隐瞒了意图╮
隐瞒了意图╮ 2020-12-09 17:14

As far as I know, there are two options about promise:

  • promise.all()

  • promise.race()

Ok, I know what promise.all()<

6条回答
  •  野趣味
    野趣味 (楼主)
    2020-12-09 17:54

    It's a piece to build a timeout system, where:

    1. the request/computation may be canceled by another channel
    2. it will still be used later, but we need an interaction now.

    For an example of the second, one might show a spinner "instantly" while still defaulting to show real content if it comes in fast enough. Try running the below a few times - note at least some console message comes "instantly". This might normally be attached to perform operations on a UI.

    The key to note is - the result of Promise.race is much less important than the side effects (though, this then is a code smell).

    // 300 ms _feels_ "instant", and flickers are bad
    
    function getUserInfo(user) {
      return new Promise((resolve, reject) => {
        // had it at 1500 to be more true-to-life, but 900 is better for testing
        setTimeout(() => resolve("user data!"), Math.floor(900*Math.random()));
      });
    }
    
    function showUserInfo(user) {
      return getUserInfo().then(info => {
        console.log("user info:", info);
        return true;
      });
    }
    
    function showSpinner() {
      console.log("please wait...")
    }
    
    function timeout(delay, result) {
      return new Promise(resolve => {
        setTimeout(() => resolve(result), delay);
      });
    }
    Promise.race([showUserInfo(), timeout(300)]).then(displayed => {
      if (!displayed) showSpinner();
    });

    Inspiration credit to a comment by captainkovalsky.

    An example of the first:

    function timeout(delay) {
      let cancel;
      const wait = new Promise(resolve => {
        const timer = setTimeout(() => resolve(false), delay);
        cancel = () => {
          clearTimeout(timer);
          resolve(true);
        };
      });
      wait.cancel = cancel;
      return wait;
    }
    
    
    function doWork() {
      const workFactor = Math.floor(600*Math.random());
      const work = timeout(workFactor);
      
      const result = work.then(canceled => {
        if (canceled)
          console.log('Work canceled');
        else
          console.log('Work done in', workFactor, 'ms');
        return !canceled;
      });
      result.cancel = work.cancel;
      return result;
    }
    
    function attemptWork() {
      const work = doWork();
      return Promise.race([work, timeout(300)])
        .then(done => {
          if (!done)
            work.cancel();
          return (done ? 'Work complete!' : 'I gave up');
      });
    }
    
    attemptWork().then(console.log);

    You can see from this one that the timeout's console.log is never executed when the timeout hits first. It should fail/succeed about half/half, for testing convenience.

提交回复
热议问题