首页 > 解决方案 > 如何在 Javascript 中为 Promise.all 编写 Polyfill 时处理 setTimeout 情况

问题描述

我正在尝试为 Promise.all 编写一个 polyfill,当我在没有 setTimeout 的情况下通过 Promise 时它工作正常,但是使用 setTimeout,我没有得到正确的结果,因为它在计时器到期之前解析并返回了 Promise。

如何处理这种情况以在以下函数中工作,与实际 Promise.all 的工作方式相同。

下面是我的代码片段和codesandbox的链接

const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => resolve("success 1"), 2000);
  });

const promise2 = new Promise((resolve, reject) => {
  resolve("success 2");
});

const promise3 = new Promise((resolve, reject) => {
  resolve("success 3");
});
    
 function resolveAll(promiseArr) {
      let arr = [];
      return new Promise((resolve, reject) => {
        promiseArr.map((each_promise, index) => {
          return each_promise
            .then((res) => {
              arr[index] = res;
              if (index === promiseArr.length - 1) {
                resolve(arr);
              }
            })
            .catch((err) => {
              reject(err);
            });
        });
      });
    }
 resolveAll([promise1, promise2, promise3])
  .then((res) => {
    console.log(res, "result");
  })
  .catch((err) => console.log(err, "error"));

实际结果:[undefined, "success 2", "success 3"]

预期结果:[“成功 1”、“成功 2”、“成功 3”]

https://codesandbox.io/s/fast-bush-6osdy?file=/src/index.js

标签: javascriptpromisesettimeoutpolyfillspromise.all

解决方案


你的问题是

if (index === promiseArr.length - 1) {
    resolve(arr);
}

只是检查最后一个承诺是否已解决,但在您的场景中,第一个承诺是由于 setTimeout 而得到解决的最后一个承诺。

一种解决方案是记录有多少承诺已经解决,例如

const promise1 = new Promise((resolve, reject) => {
    setTimeout(() => resolve("success 1"), 2000);
});

const promise2 = new Promise((resolve, reject) => {
    resolve("success 2");
});

const promise3 = new Promise((resolve, reject) => {
  resolve("success 3");
});

function resolveAll(promiseArr) {
    let arr = [],
    errorMsg = [],
    resolvedPromiseCount = 0;

    return new Promise((resolve, reject) => {
        promiseArr.map((each_promise, index) => {
            return each_promise.then((res) => {
                console.log(res)
                arr[index] = res;
                resolvedPromiseCount++;

                if (resolvedPromiseCount === promiseArr.length) {
                    resolve(arr);
                }
            })
            .catch((err) => {
                resolvedPromiseCount++;
                errorMsg.push(err);
            });
        });
    });
}

resolveAll([promise1, promise2, promise3]).then((res) => {
    console.log(res, "result");
})
.catch((err) => console.log(err, "error"));

推荐阅读