簡體   English   中英

承諾鏈中承諾之間的延遲

[英]Delays between promises in promise chain

假設我正在使用以下代碼連續運行幾個 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(它返回一個承諾),等待承諾得到解決,然后再次調用 mySpecialFunction 等等。因此,該函數以正確的順序為數組中的每個元素調用一次。

我如何確保每次調用mySpecialFunction(item)之間至少有 50 毫秒的延遲?

以正確的順序執行承諾很重要,並且mySpecialFunction的執行時間每次都不同。

我猜同步睡眠會起作用,但我不打算在單獨的線程中運行此代碼,因此它會導致瀏覽器中煩人的 ui 凍結。

我不確定 setTimer 是否可以用於此目的。 我的意思是我不能推遲承諾的回報。

答案很好,但它們等待的時間太長,因為無論實際操作是否已經花費了 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());

一個非常方便的實用函數是我稱之為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
});

要獲得至少50 毫秒的延遲,請使用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());

下面顯示了如何實現不阻塞但等待指定時間段的承諾的示例:

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())

給你: 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 毫秒延遲只是為了強調。

因為這似乎是mySpecialFunction的要求, 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 毫秒的延遲。

這是我針對延遲承諾序列的完整解決方案:


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);

    });


  }

它接收一系列承諾和它們之間以毫秒為單位的超時延遲,作為參數。

希望,它會幫助你!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM