【前端100問】Q80:介紹下 Promise.all 使用、原理實現及錯誤處理

寫在前面

此係列來源於開源項目:前端 100 問:能搞懂 80%的請把簡歷給我
爲了備戰 2021 春招
每天一題,督促自己
從多方面多角度總結答案,豐富知識
介紹下 Promise.all 使用、原理實現及錯誤處理
簡書整合地址:前端 100 問

正文回答

Promise 概念

Promise 是 JS 異步編程中的重要概念,異步抽象處理對象,是目前比較流行 Javascript 異步編程解決方案之一。Promise.all()接受一個由 promise 任務組成的數組,可以同時處理多個 promise 任務,當所有的任務都執行完成時,Promise.all()返回 resolve,但當有一個失敗(reject),則返回失敗的信息,即使其他 promise 執行成功,也會返回失敗。和後臺的事務類似。和 rxjs 中的 forkJoin 方法類似,合併多個 Observable 對象 ,等到所有的 Observable 都完成後,才一次性返回值。

Promise.all 如何使用
// 以下 demo,請求兩個 url,當兩個異步請求返還結果後,再請求第三個 url
const p1 = request(`http://some.url.1`);
const p2 = request(`http://some.url.2`);
Promise.all([p1, p2])
  .then((datas) => {
    // 此處 datas 爲調用 p1, p2 後的結果的數組
    return request(`http://some.url.3?a=${datas[0]}&b=${datas[1]}`);
  })
  .then((data) => {
    console.log(data);
  });
Promise.all 原理實現
function promiseAll(promises) {
  return new Promise(function (resolve, reject) {
    if (!Array.isArray(promises)) {
      return reject(new TypeError("argument must be anarray"))
    }
    var countNum = 0;
    var promiseNum = promises.length;
    var resolvedvalue = new Array(promiseNum);
    for (var i = 0; i < promiseNum; i++) {
      (function (i) {
        Promise.resolve(promises[i]).then(function (value) {
          countNum++;
          resolvedvalue[i] = value;
          if (countNum === promiseNum) {
            return resolve(resolvedvalue)
          }
        }, function (reason) {
          return reject(reason)
        )
      })(i)
    }
  })
}

var p1 = Promise.resolve(1),
  p2 = Promise.resolve(2),
  p3 = Promise.resolve(3);
promiseAll([p1, p2, p3]).then(function (value) {
  console.log(value)
})
Promise.all 錯誤處理

有時候我們使用 Promise.all()執行很多個網絡請求,可能有一個請求出錯,但我們並不希望其他的網絡請求也返回 reject,要錯都錯,這樣顯然是不合理的。如何做才能做到 promise.all 中即使一個 promise 程序 reject,promise.all 依然能把其他數據正確返回呢?

1、全部改爲串行調用(失去了 node 併發優勢)

2、當 promise 捕獲到 error 的時候,代碼喫掉這個異常,返回 resolve,約定特殊格式表示這個調用成功了

var p1 = new Promise(function (resolve, reject) {
  setTimeout(function () {
    resolve(1);
  }, 0);
});
var p2 = new Promise(function (resolve, reject) {
  setTimeout(function () {
    resolve(2);
  }, 200);
});
var p3 = new Promise(function (resolve, reject) {
  setTimeout(function () {
    try {
      console.log(XX.BBB);
    } catch (exp) {
      resolve("error");
    }
  }, 100);
});
Promise.all([p1, p2, p3])
  .then(function (results) {
    console.log("success");
    console.log(results);
  })
  .catch(function (r) {
    console.log("err");
    console.log(r);
  });
說 all 體驗不好,那我們也可以自己做一個 some 方法,表示全部失敗纔算失敗
Promise.some = function (promiseArrs) {
  return new Promise((resolve, reject) => {
    let arr = []; //定義一個空數組存放結果
    let i = 0;
    function handleErr(index, err) {
      //處理錯誤函數
      arr[index] = err;
      i++;
      if (i === promiseArrs.length) {
        //當i等於傳遞的數組的長度時
        reject(err); //執行reject,並將結果放入
      }
    }
    for (let i = 0; i < promiseArrs.length; i++) {
      //循環遍歷數組
      promiseArrs[i].then(resolve, (e) => handleErr(i, e));
    }
  });
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章