【问题标题】:Delays between promises in promise chain承诺链中承诺之间的延迟
【发布时间】:2017-04-26 01:16:39
【问题描述】:

假设我正在使用以下代码连续运行几个 Promise:

let paramerterArr = ['a','b','c','d','e','f']
parameterArr.reduce(function(promise, item) {
  return promise.then(function(result) {
    return mySpecialFunction(item);
  })
}, Promise.resolve())

代码只是简单地调用 mySpecialFunction(它返回一个 Promise),等待 Promise 被解析,然后再次调用 mySpecialFunction 等等。因此,该函数以正确的顺序为数组中的每个元素调用一次。

如何确保每次调用 mySpecialFunction(item) 之间至少有 50 毫秒的延迟?

以正确的顺序执行 promise 很重要,mySpecialFunction 的执行时间每次都不同。

我猜同步睡眠会起作用,但我不打算在单独的线程中运行这段代码,所以它会导致浏览器中烦人的 ui 冻结。

我不确定 setTimer 是否可以用于此目的。我的意思是我不能延迟承诺的回报。

【问题讨论】:

标签: javascript ecmascript-6 promise delay es6-promise


【解决方案1】:

答案很好,但它们等待的时间太长,因为所有答案都等待实际操作是否已经花费了超过 50 毫秒。

您可以使用Promise.all

const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
let parameterArr = ['a','b','c','d','e','f'];
parameterArr.reduce(function(promise, item) {
  return promise.then(function(result) {
    return Promise.all([delay(50), myPromise(item)]);
  });
}, Promise.resolve());

【讨论】:

  • 比我快 37 秒 :-)
【解决方案2】:

我称之为delay()

function delay(t, val) {
    return new Promise(function(resolve) {
        if (t <= 0) {
            resolve(val);
        } else {
            setTimeout(resolve.bind(null, val), t);
        }
    });
}

然后,您可以像这样在承诺链中使用它:

let paramerterArr = ['a','b','c','d','e','f']
parameterArr.reduce(function(promise, item, index) {
  return promise.then(function(result) {
    // no delay on first iteration
    var delayT = index ? 50 : 0;
    return delay(delayT, item).then(mySpecialFunction);
  })
}, Promise.resolve());

您还可以创建一个小实用函数来执行带有可选延迟的顺序迭代:

// delayT is optional (defaults to 0)
function iterateSerialAsync(array, delayT, fn) {
    if (!fn) {
        fn = delayT;
        delayT = 0;
    }
    array.reduce(function(p, item, index) {
        return p.then(function() {
            // no delay on first iteration
            if (index === 0) delayT = 0;
            return delay(delayT, item).then(fn)
        });
    }, Promise.resolve());
}

然后,你会像这样使用它:

iterateSerialAsync(paramerterArr, 50, mySpecialFunction).then(function(finalVal) {
    // all done here
});

【讨论】:

    【解决方案3】:

    要获得至少 50ms 的延迟,请使用Promise.all

    function delay(t) {
      return new Promise(function(resolve) {
        setTimeout(resolve, t);
      });
    }
    parameterArr.reduce(function(promise, item) {
      return promise.then(function() {
        return Promise.all([
          mySpecialFunction(item),
          delay(50)
        ]);
      });
    }, Promise.resolve());
    

    【讨论】:

      【解决方案4】:

      以下示例说明了如何实现不阻塞但等待指定时间段的承诺:

      function timedPromise(ms, payload) {
          return new Promise(function(resolve) {
              setTimeout(function() {
                  resolve(payload);
              }, ms);
          })
      }
      
      
      var time = Date.now();
      
      timedPromise(1000)
          .then(function() {
              console.log(time - Date.now());
              return timedPromise(2000);
          }).then(function() {
              console.log(time - Date.now());
              return timedPromise(3000);
          });
      

      因此,根据您的具体需求,您应该能够执行以下操作:

      let paramerterArr = ['a','b','c','d','e','f']
      parameterArr.reduce(function(promise, item) {
        return promise.then(function(result) {
          return mySpecialFunction(item);
        }).then(function(specialResult) {
          return timedPromise(50, specialResult);
        });
      }, Promise.resolve())
      

      【讨论】:

        【解决方案5】:

        给你:https://jsbin.com/suvasox/edit?html,js,console

        let paramerterArr = ['a','b','c','d','e','f']
        paramerterArr.reduce((p, val) => {
          return p.then(() => {
            return new Promise((res) => {
              setTimeout(() => { res(mySpecialFunction(val)); }, 1000); 
            });
          });
        }, Promise.resolve());
        

        p 必须是 p.then() 的结果。只有这样你才能链接承诺。

        注意,我将其更改为 1000 毫秒延迟只是为了强调。

        【讨论】:

          【解决方案6】:

          因为这似乎是mySpecialFunction 的要求,所以我会在那里实现它。这样如果函数在最后一次调用后不到 50 毫秒被调用,就会延迟自己

          const delayBetweenCalls = (delay, fn) => {
              let lastCall = NaN;
              return function(/*...arguments*/){
                  //this and arguments are both forwarded to fn
          
                  return new Promise(resolve => {
                      let poll = () => {
                          let delta = Date.now() - lastCall;
                          if(delta < delay){
                              setTimeout(poll, delta - delay);
                          }else{
                              lastCall = Date.now();
                              resolve( fn.apply(this, arguments) );
                          }
                      }
                      poll();
                  })
              }
          }
          

          然后:

          const mySpecialFunction = delayBetweenCalls(50, function(some, ...args){
              return someValueOrPromise;
          });
          
          //and your loop stays the same:
          parameterArr.reduce(function(promise, item) {
              return promise.then(function(result) {
                  return mySpecialFunction(item);
              })
          }, Promise.resolve())
          

          所以无论在哪里/如何调用mySpecialFunction 都无关紧要,在它运行传递的回调中的代码之前总会有至少 50 毫秒的延迟。

          【讨论】:

            【解决方案7】:

            这是我对延迟承诺序列的完整解决方案:

            
            function timeout_sequence_promise(promises = [], timeout = 200) {
            
                //fake promise used as buffer between promises from params
                const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
            
                //we need to create array of all promises with delayed buffers
                let delayed_promises = [];
            
                let total = promises.length;
            
                let current = 0;
            
                //every odd promise will be buffer
                while (current < total) {
            
                  delayed_promises.push(promises[current]);
                  delayed_promises.push(delay(timeout));
            
                  current++;
            
                }
            
                return Promise.all(delayed_promises).then((result) => {
            
                  //we need to filter results from empty odd promises
                  return result.filter((item, index) => (index+2)%2 === 0);
            
                });
            
            
              }
            
            

            它接收承诺数组和它们之间的超时延迟(毫秒)作为参数。

            希望对你有帮助!

            【讨论】:

              猜你喜欢
              • 2016-12-08
              • 1970-01-01
              • 2015-03-27
              • 2023-03-21
              • 1970-01-01
              • 1970-01-01
              • 2018-05-05
              • 2015-08-25
              相关资源
              最近更新 更多