尝试定义 promise.all

Trying to define a promise.all

我试图通过创建本书练习中的 Promise.all 方法来理解 promise 的工作原理: https://eloquentjavascript.net/11_async.html#i_Ug+Dv9Mmsw

我尝试遍历作为方法本身的参数给出的整个数组,使用 .then 进行成功的承诺,其中处理程序的主体将结果推送到我之前在循环外定义的绑定,用于拒绝的承诺,我使用 .catch 的方式是将被拒绝的值作为 "reason" 并拒绝给它一个错误的主要承诺

function Promise_all(promises) {
  return new Promise((resolve, reject) => {
    if(promises.length == 0) resolve(promises);
    let fullArray = [];

    for(let i=0; i<promises.length ; i++){
         promises[i]
        .then(x => fullArray.push(x))
        .catch(reason => reject(new Error(reason)));
    }
    resolve(fullArray);
  });
}

我希望函数执行以下操作:

-从"Promises"数组中选择一个promise。

-通过在其上使用 .then 方法和处理函数来解决承诺(如果成功),该处理函数仅将结果推送到 "fullArray".

-通过在其上使用 .catch 方法和一个处理函数来解决承诺(如果被拒绝),该处理函数只需调用将由 "Promise_all" 编辑的主要承诺的拒绝处理程序.

-当循环结束时,只需解析成功承诺的 "fullArray" 个承诺。

代码根本没有像我想的那样工作,使用本书的测试代码没有return预期的结果:

Promise_all([]).then(array => {
  console.log("This should be []:", array);
});
function soon(val) {
  return new Promise(resolve => {
    setTimeout(() => resolve(val), Math.random() * 500);
  });
}
Promise_all([soon(1), soon(2), soon(3)]).then(array => {
  console.log("This should be [1, 2, 3]:", array);
});
Promise_all([soon(1), Promise.reject("X"), soon(3)])
  .then(array => {
    console.log("We should not get here");
  })
  .catch(error => {
    if (error != "X") {
      console.log("Unexpected failure:", error);
    }
  });

正如@Bergi 所说,代码的问题在于“.then”和“.catch”回调是异步调用的,因此,"fullArray" 甚至在"resolve()" 即使在循环之外也会被调用。为了解决这个问题,我简单地在最后完成的承诺中添加了 "resolve()",为此,我简单地添加了一个 "counter" 绑定,它的值是 "promises" 数组的长度,并且每次在承诺中调用“.then”时减 1,当此 "counter" 等于 0 时,它调用 "resolve()".

但这只解决了用承诺填充 "fullArray" 的问题,而不是这些承诺按调用顺序正确排序的问题,为了解决这个问题,我只是在数组中枚举它们循环的 "i" 绑定,最终结果是这样的:

function Promise_all(promises) {
  return new Promise((resolve, reject) => {
    if(promises.length == 0) resolve(promises);
    let fullArray = [],
        counter = promises.length;

    for(let i=0; i< promises.length ; i++){
         promises[i]
        .then(x => {
           fullArray[i] = x;
           counter--;
           if(counter == 0) resolve(fullArray)})
        .catch(reason => reject(new Error(reason)));
    }
  });
}