首页 > 解决方案 > Javascript 承诺:监控数组的状态

问题描述

假设我在 Javascript 中有一系列 Promise,我希望它们n一次解决 Promise。有什么好方法可以做到这一点?

我可以调用一个状态数组promisesInProgress并让每个承诺监控它的长度吗?在外面,我将使用 Promise.all()。但是在每个 promise 中,我希望它检查状态数组 promisesInProgress,并且仅在该数组的长度小于 n 时触发。那行得通吗?

如果我想确保这些承诺不会解决得太快,限制它们怎么办?

这有一个好的模式吗?

标签: javascriptpromise

解决方案


Promise 一出现就“运行”,所以当你有一个数组时,你不能期望延迟其中的一些。

但是,您可以做的是使用一组函数,当调用这些函数时,它们会返回一个新的 Promise。该max参数将确定您实际立即调用的这些函数中有多少,而其余函数仅在其中一个承诺解决后“房间”变得可用时才被调用。

您可以这样做:

// Main function. 
// Parameters:
// - the maximum number of unresolved promises that may exist at a given time
// - an array of promise-creating functions 
function throttle(maxPending, asyncFuncs) {
    return new Promise((resolve, reject) => {
        let numPending = 0;
        let nextFuncId = 0;
        const promisedValues = [];
        (function check() {
            if (nextFuncId >= asyncFuncs.length) { // All promises created
                if (numPending == 0) resolve(promisedValues); // All promises fulfilled
                return;
            }
            while (numPending < maxPending) { // Room for creating promise(s)
                numPending++;
                const thisFuncId = nextFuncId++;
                asyncFuncs[thisFuncId]().then(value => {
                    promisedValues[thisFuncId] = value;
                    numPending--;
                    check();
                }).catch(reject);
            }
        })();
    });
}

// Demo: 
// The usual delay function: returns a promise that resolves after given delay
const delay = (ms) => {
    console.log("Start delay of " + ms + "ms");
    return new Promise(resolve => setTimeout(resolve, ms))
            .then(() => console.log("End delay of " + ms + "ms"));
};

// Curry for the above: pass the milliseconds and return a function 
//   that can create a promise for it
const delayF = (ms) => delay.bind(null, ms);

// Pass 5 promise-creating functions, but only allow 3 concurrently pending promises:
throttle(3, [delayF(1000), delayF(500), delayF(800), delayF(300), delayF(900)])
    .then(() => console.log("all done"));  


推荐阅读