首页 > 解决方案 > 试图定义一个 promise.all

问题描述

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

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

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

我期望该功能执行以下操作:

- 从“承诺”数组中选择一个承诺。

- 通过使用 .then 方法和处理函数来解决承诺(如果成功),该处理函数只是将结果推送到“fullArray”。

- 通过使用 .catch 方法和一个处理函数来解决承诺(如果被拒绝),该处理函数简单地调用将由“Promise_all”返回的主承诺的拒绝处理程序。

- 当循环结束时,只需将成功的 promise 的“fullArray”解析为 promise。

代码根本不像我想象的那样工作,使用本书的测试代码不会返回预期的结果:

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

标签: javascriptpromisees6-promise

解决方案


正如@Bergi 所说,代码的问题是“.then”和“.catch”回调是异步调用的,因此,在调用“resolve()”时甚至没有填充“fullArray”即使它在循环之外。为了解决这个问题,我只是在最后完成的 Promise 中添加了“resolve()”,为此,我只是添加了一个“counter”绑定,该绑定具有“promises”数组的长度值,并减少了每次在 promise 上调用 ".then" 时为 1,当这个 "counter" 等于 0 时,它调用 "resolve()"。

但这只能解决用 Promise 填充“fullArray”的问题,而不是那些 Promise 按它们被调用的顺序正确排序的问题,为了解决这个问题,我只需使用“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)));
    }
  });
}

推荐阅读