前端入門11 -- JavaScript之Promise

回調(diào)函數(shù)

  • 回調(diào)函數(shù)分為兩種類型,分別為同步回調(diào)與異步回調(diào);
  • 同步回調(diào):會立即執(zhí)行,完全執(zhí)行完了才結(jié)束,不會放入回調(diào)隊列中;
  • 異步回調(diào):不會立即執(zhí)行,會放入回調(diào)隊列中 將來執(zhí)行;
  <script>

    //同步回調(diào)
    const arr = [1, 3, 5];
    arr.forEach((item) => {
      console.log(item);
    });
    console.log('forEach(之后)');

    //異步回調(diào)
    setTimeout(() => {
      console.log('異步回調(diào)');
    }, 0);
    console.log('setTimeout()之后');

  </script>
  • 遍歷回調(diào)屬于同步回調(diào),立即執(zhí)行;
  • 定時器中的回調(diào)屬于異步回調(diào),不會立即執(zhí)行;

常見的內(nèi)置錯誤

  • Error:所有錯誤的父類型;
  • ReferenceError:引用變量不存在;
  • TypeError:數(shù)據(jù)類型不正確;
  • RangeError:數(shù)據(jù)值不在其所允許的范圍之內(nèi);
  • SyntaxError:語法錯誤;
  <script>
    //1.ReferenceError:引用變量不存在
    console.log(a); //ReferenceError: a is not defined

    //2.TypeError:數(shù)據(jù)類型不正確
    let b = {};
    b.xxx(); //TypeError: b.xxx is not a function

    //3.RangeError:數(shù)據(jù)值不在其所允許的范圍之內(nèi)
    function func() {
      func()
    }
    func(); //RangeError: Maximum call stack size exceeded

    //4.SyntaxError:語法錯誤
    const c = """"; //SyntaxError: Unexpected string
  </script>
錯誤的處理
  • 錯誤處理的方式有兩種:捕獲錯誤和拋出錯誤;
  • 捕獲錯誤:try ... catch;
<script>

    try {
      let b;
      console.log(b.xxx);
    } catch (error) {
      console.log(error.message);
      console.log(error.stack);
    }
    console.log('出錯之后');

  </script>
  • 拋出錯誤:throw error,錯誤由調(diào)用者進行處理;
  <script>

    function something() {
      if (Date.now % 2 === 1) {
        console.log('當(dāng)前時間為奇數(shù),可以執(zhí)行任務(wù)');
      } else {
        throw new Error('當(dāng)前時間為偶數(shù),拋出異常 無法執(zhí)行任務(wù)');
      }
    }

    //拋出錯誤之后 調(diào)用者來處理了
    try {
      something();
    } catch (error) {
      alert(error.message);
    }

  </script>

Promise

  • Promise是JS中進行異步編程的一種解決方案;
  • 從語法上來說,Promise是一個構(gòu)造函數(shù);
  • 從功能上來說,Promise對象用來封裝一個異步操作并可以獲取其結(jié)果;
Promise的狀態(tài)
  • 初始化狀態(tài)為pending;
    • pending變?yōu)閞esolved;
    • pending變?yōu)閞eiected;
  • 一個Promise對象,其狀態(tài)只能改變一次,無論變?yōu)槌晒€是失敗,都會有一個結(jié)果數(shù)據(jù),成功的結(jié)果數(shù)據(jù)一般稱為value,失敗的結(jié)果數(shù)據(jù)一般稱為reason;
  • Promise執(zhí)行的基本流程如下:
image.png
Promise的基本使用
  • 首先創(chuàng)建Promise實例對象;
  • 在執(zhí)行器中執(zhí)行異步任務(wù);
  • 獲取異步任務(wù)的處理結(jié)果;
  <script>
    //1.創(chuàng)建Promise實例對象
    const promise = new Promise((resolve, reject) => {
      //2.在執(zhí)行器中 執(zhí)行異步任務(wù)
      setTimeout(() => {
        const time = Date.now();
        if (time % 2 === 0) {
          resolve('成功的數(shù)據(jù),time = ' + time);
        } else {
          reject('失敗的數(shù)據(jù),time = ' + time);
        }
      })
    }, 1000);

    //3.處理異步任務(wù)的結(jié)果
    promise.then(
      value => {
        console.log('成功的回調(diào)', value);
      },
      reason => {
        console.log('失敗的回調(diào)', reason);
      }
    )
  </script>
Promise的優(yōu)點
  • 首先Promise指定回調(diào)函數(shù)的方式更加靈活;
    • 純回調(diào)函數(shù)形式,指定回調(diào)函數(shù)必須在異步任務(wù)執(zhí)行之前;
    • Promise形式,指定回調(diào)函數(shù)在執(zhí)行異步任務(wù)前后均可以,更加靈活;
  • 其次Promise支持鏈?zhǔn)秸{(diào)用,可以解決回調(diào)地獄問題,終極解決方案為:async/await;
  <script>
    //1.使用純回調(diào)函數(shù)的形式
    function successCallback(result) {
      console.log('成功結(jié)果:' + result);
    }
    function failCallback(error) {
      console.log('失敗原因:' + error);
    }

    //必須在異步任務(wù)執(zhí)行之前 指定回調(diào)函數(shù)
    createAudioFileAsync(audioSettings, successCallback, failCallback);

    //2.使用Promise的形式
    const promise = createAudioFileAsync(audioSettings);
    //指定回調(diào)函數(shù) 非常靈活 可以在異步任務(wù)執(zhí)行前后 指定均可以
    promise.then(successCallback, failCallback);

  </script>
  <script>

    function failCallback(error) {
      console.log('失敗原因:' + error);
    }

    //案例:三個請求 依次依賴
    //1.回調(diào)嵌套地獄 下一層函數(shù)的調(diào)用 依賴上一層函數(shù)的結(jié)果
    doFirstThing(function (result) {
      doSecondThing(result, function (newResult) {
        doThirdThing(newResult, function (lastResult) {
          console.log('lastResult =', lastResult);
        }, failCallback);
      }, failCallback);
    }, failCallback);

    //2.使用Promise鏈?zhǔn)秸{(diào)用 解決回調(diào)地獄問題
    doFirstThing()
      .then(function (result) {
        return doSecondThing(result);
      })
      .then(function (newResult) {
        return doThirdThing(newResult);
      })
      .then(function (lastResult) {
        console.log('lastResult =', lastResult);
      })
      .catch(failCallback);

      //3.回調(diào)地獄的終極解決方案: async/await 
      async function request() {
        try {
          const result = await doFirstThing();
          const newResult = await doSecondThing(result);
          const lastResult = await doThirdThing(newResult);
          console.log('lastResult =', lastResult);
        } catch (error) {
          failCallback(error);
        }
      }

  </script>
Promise常見API
image.png
  <script>

    //then value   -->   異步執(zhí)行成功
    //catch reason --> 異步執(zhí)行失敗
    new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('111111');
      }, 5000);
    }).then((value) => {
      console.log(value);
    }).catch((reason) => {
      console.log(reason);
    });

    //Promise.resolve() 或者 Promise.reject() 均會返回一個Promise實例對象
    const p1 = new Promise((resolve, reject) => {
      resolve(1);
    });
    const p2 = Promise.resolve(2);
    const p3 = Promise.reject(3);

    p1.then(value => console.log(value));
    p2.then(value => console.log(value));
    p3.catch(reason => console.log(reason));

    //pAll 數(shù)組中異步操作只要有一個失敗 就直接失敗
    const pAll = Promise.all([p1, p2, p3]);
    pAll.then(
      value => {
        console.log('all onResolve()', value);
      },
      reason => {
        console.log('all onReject()', reason);
      }
    )

    //異步操作數(shù)組中的  某個異步操作最先返回結(jié)果 就是pRace的最終結(jié)果
    const pRace = Promise.race([p1, p2, p3]);
    pRace.then(
      value => {
        console.log('all onResolve()', value);
      },
      reason => {
        console.log('all onReject()', reason);
      }
    )
    
  </script>
  • Promise.resolve(value):返回值為一個新的promise,參數(shù)value值可以是promise,可以是非promise
    • 當(dāng)value為非promise時,那么新promise的狀態(tài)結(jié)果為resolve成功;
    • 當(dāng)value為promise時,那么新promise的狀態(tài)結(jié)果為value的狀態(tài)結(jié)果;
  • Promise.reject(value):返回值為一個新的promise,其狀態(tài)結(jié)果為reject失??;
  • Promise.all(promise數(shù)組):返回值為一個新的promise,其狀態(tài)結(jié)果為:
    • 當(dāng)promise數(shù)組中存在一個狀態(tài)失敗的,那么新promise的狀態(tài)結(jié)果為失??;
    • 當(dāng)promise數(shù)組中都成功,那么新promise的狀態(tài)結(jié)果為一個數(shù)組集合值;
  • Promise.race(promise數(shù)組):返回值為一個新的promise,其狀態(tài)結(jié)果為:promise數(shù)組中先返回狀態(tài)結(jié)果的promise的狀態(tài)結(jié)果;

Promise的使用注意事項

  • promise的狀態(tài)改變分為三種情況:
    • 執(zhí)行成功resolve(value),pending --> resolve;
    • 執(zhí)行失敗reject(reason),pending --> reject;
    • 拋出異常 throw error,pending --> reject;
  • 一個promise對象,可以指定多個狀態(tài)回調(diào),且多個狀態(tài)回調(diào)都會執(zhí)行;
  <script>

    const p = new Promise((resolve, reject) => {
      // resolve(1); //成功  pending --> resolve
      // reject(2);  //失敗  pending --> reject
      throw new Error('報錯了'); //拋出異常 pending --> reject
    });
    //promise指定多個回調(diào) 都會調(diào)用
    p.then(
      value => { },
      reason => { console.log('reason', reason) }
    );
    p.then(
      value => { },
      reason => { console.log('reason', reason) }
    );
  </script>
  • 如何控制改變promise狀態(tài)指定回調(diào)函數(shù)的先后順序?
    • 常規(guī)情況下:先指定回調(diào)函數(shù),再改變promise狀態(tài),執(zhí)行回調(diào)函數(shù);
  <script>

    //先指定回調(diào)函數(shù) 再改變狀態(tài)
    new Promise((resolve, reject) => {
      //2.異步執(zhí)行 再改變狀態(tài)(同時指定數(shù)據(jù)) 異步執(zhí)行下面指定的回調(diào)函數(shù)
      setTimeout(() => {
        resolve(1);
      })
    }).then(
      //1.先指定回調(diào)函數(shù),promise會保存當(dāng)前指定的回調(diào)函數(shù)
      value => { console.log('value', value) },
      reason => { console.log('reason', reason) }
    );

    //先指定回調(diào)函數(shù) 再改變狀態(tài)
    new Promise((resolve, reject) => {
      //1.先改變狀態(tài)(同時指定數(shù)據(jù))
      resolve(1);
    }).then(
      //2.后指定回調(diào)函數(shù) 異步執(zhí)行回調(diào)函數(shù)
      value => { console.log('value', value) },
      reason => { console.log('reason', reason) }
    );

    //先指定回調(diào)函數(shù) 再改變狀態(tài)
    const p = new Promise((resolve, reject) => {
      //2.異步執(zhí)行 再改變狀態(tài)(同時指定數(shù)據(jù)) 異步執(zhí)行下面指定的回調(diào)函數(shù)
      setTimeout(() => {
        resolve(1);
      })
    });

    setTimeout(() => {
      p.then(
        //1.先指定回調(diào)函數(shù),promise會保存當(dāng)前指定的回調(diào)函數(shù)
        value => { console.log('value', value) },
        reason => { console.log('reason', reason) }
      );
    }, 2000);

  </script>
  • promise.then()會返回一個新的promise對象,此promise的狀態(tài)結(jié)果由什么決定?
    • 由then()指定的回調(diào)函數(shù)執(zhí)行的結(jié)果決定;
    • then()指定的回調(diào)函數(shù),沒有返回值,則新的promise對象狀態(tài)變成resolve,value值為undefined;
    • then()指定的回調(diào)函數(shù),返回非promise的任意值value,則新的promise對象狀態(tài)變成resolve,會執(zhí)行成功的回調(diào),且獲取value值;
    • then()指定的回調(diào)函數(shù),拋出異常,則新的promise對象狀態(tài)變成reject,會執(zhí)行失敗的回調(diào);
    • then()指定的回調(diào)函數(shù),返回另一個新的promise,則此promise的狀態(tài)結(jié)果會成為新promise的狀態(tài)結(jié)果;
  <script>

    new Promise((resolve, reject) => {
      resolve(1);
    }).then(
      value => { console.log('onResolved1', value) },
      reason => { 
        console.log('onRejected1', reason) 
        // return 2;
        // return Promise.resolve(3);
        // return Promise.reject(4);
        // throw 5;
      }
    ).then(
      value => { console.log('onResolved2', value) },
      reason => { console.log('onRejected2', reason) }
    );

  </script>
  • promise如何串聯(lián)多個操作任務(wù)?
    • promise.then()可返回一個新的promise;
    • promise.then()的鏈?zhǔn)秸{(diào)用可串聯(lián)多個同步/異步任務(wù);
  <script>

    new Promise((resolve, reject) => {
      setTimeout(() => {
        console.log('執(zhí)行異步任務(wù)1');
        resolve(1);
      }, 1000);
    }).then(
      value => {
        console.log('異步任務(wù)1的結(jié)果:', value);
        console.log('執(zhí)行同步任務(wù)2');
        return 2;
      },
      reason => {
        console.log('onRejected1', reason);
      }
    ).then(
      value => {
        console.log('同步任務(wù)2的結(jié)果:', value);
        return new Promise((resolve, reject) => {
          setTimeout(() => {
            console.log('執(zhí)行異步任務(wù)3');
            resolve(3);
          }, 1000);
        })
      },
      reason => {
        console.log('onRejected2', reason);
      }
    ).then(
      value => {
        console.log('異步任務(wù)3的結(jié)果:', value);
      }
    );

  </script>
image.png
  • promise的異常傳透:
    • 當(dāng)使用promise的then鏈?zhǔn)秸{(diào)用時,可以再最后指定失敗的回調(diào);
    • 前面任何操作出現(xiàn)了異常,都會傳到最后失敗的回調(diào);
  <script>

    new Promise((resolve, reject) => {
      reject(1);
    }).then(
      value => {
        console.log('onResolve1:', value);
        return 2;
      },
      // reason => {
      //   throw reason;
      // }
    ).then(
      value => {
        console.log('onResolve2:', value);
        return 3;
      },
      // reason => {
      //   throw reason;
      // }
    ).then(
      value => {
        console.log('onResolve3:', value);
      },
      // reason => {
      //   throw reason;
      // }
    ).catch(
      reason => {
        console.log('onReject: ', reason);
      }
    )

  </script>
  • . catch失敗處理,上面沒有失敗的處理,就會執(zhí)行. catch中的代碼,沒有失敗的處理等價于reason => { throw reason },拋出了異常,然后一直往下傳遞異常,最終會執(zhí)行. catch中的代碼;
  • 如何中斷promise鏈?
    • 當(dāng)使用promise的then鏈?zhǔn)秸{(diào)用時,在中間中斷,不再調(diào)用后面的回調(diào)函數(shù);
    • 方案:在回調(diào)函數(shù)中返回一個pending狀態(tài)的promise對象;
  <script>

    new Promise((resolve, reject) => {
      reject(1);
    }).then(
      value => {
        console.log('onResolve1:', value);
        return 2;
      },
    ).then(
      value => {
        console.log('onResolve2:', value);
        return 3;
      },
    ).then(
      value => {
        console.log('onResolve3:', value);
      },
    ).catch(
      reason => {
        console.log('onReject1: ', reason);
        // throw reason;
        // return Promise.reject(3);
        //返回一個pending狀態(tài)的promise
        //下面的回調(diào)函數(shù)不會執(zhí)行
        return new Promise(() => { });
      }
    ).then(
      value => {
        console.log('onResolve3:', value);
      },
      reason => {
        console.log('onReject2: ', reason);
      }
    )

  </script>
  • 注意.catch()函數(shù)也會返回一個新的promise對象;

自定義Promise

  • 函數(shù)對象,代碼如下:
//自定義Promise函數(shù)模塊
(function (window) {

  const PENDING = 'pending';
  const RESOLVED = 'resolved';
  const REJECTED = 'rejected';

  //Promise的構(gòu)造函數(shù)
  function Promise(excutor) {
    const self = this;
    //promise狀態(tài) 初始化為pending
    self.status = PENDING;
    //promise異步操作的結(jié)果數(shù)據(jù)
    self.data = undefined;
    //promise的回調(diào)函數(shù)
    self.callbacks = [];

    function resolve(value) {
      if (self.status !== PENDING) {
        return;
      }
      //將狀態(tài)改成resolved
      self.status = RESOLVED;
      self.data = value;
      //若存在callback回調(diào)函數(shù),則立即異步執(zhí)行回調(diào)函數(shù)
      if (self.callbacks.length > 0) {
        setTimeout(() => {
          self.callbacks.forEach(element => {
            element.onResolved(value);
          });
        });
      }
    }

    function reject(reason) {
      if (self.status !== PENDING) {
        return;
      }
      self.status = REJECTED;
      self.data = reason;
      if (self.callbacks.length > 0) {
        setTimeout(() => {
          self.callbacks.forEach(element => {
            element.onRejected(reason);
          });
        });
      }
    }

    try {
      excutor(resolve, reject);
    } catch (error) {
      //捕獲異常了 執(zhí)行reject方法 狀態(tài)成為rejected
      reject(error);
    }
  }

  //Promise原型上的函數(shù)方法
  Promise.prototype.then = function (onResolved, onRejected) {
    //當(dāng)前promise對象
    const self = this;

    onResolved = typeof onResolved === 'function' ? onResolved : value => value;
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };

    //返回一個新的promise對象
    return new Promise((resolve, reject) => {
      //處理函數(shù)
      function handle(callback) {
        //新promise對象的狀態(tài)結(jié)果 由當(dāng)前promise對象的狀態(tài)結(jié)果決定
        //1.當(dāng)前promise結(jié)果為拋出異常,則新的promise結(jié)果為失敗,值為異常error
        //2.當(dāng)前promise結(jié)果為非promise,則新的promise結(jié)果為成功,值為異常value
        //3.當(dāng)前promise結(jié)果為promise,則新的promise結(jié)果為promise的結(jié)果
        try {
          const result = callback(self.data);
          if (result instanceof Promise) {
            result.then(resolve, reject);
          } else {
            resolve(result);
          }
        } catch (error) {
          reject(error);
        }
      }

      if (this.status === RESOLVED) {
        //立即異步執(zhí)行 當(dāng)前promise對象 成功的回調(diào)函數(shù)
        setTimeout(() => {
          handle(onResolved);
        });
      } else if (self.status === REJECTED) {
        setTimeout(() => {
          handle(onRejected);
        });
      } else {
        //將成功和失敗的回調(diào)函數(shù)保存到callbacks容器中
        self.callbacks.push({
          onResolved(value) {
            handle(onResolved);
          },
          onRejected(reason) {
            handle(onRejected);
          }
        });
      }
    });

    if (self.status === PENDING) {
      //保存回調(diào)方法 到一個對象中
      self.callbacks.push({
        onResolved,
        onRejected
      })
    } else if (self.status === RESOLVED) {
      setTimeout(() => {
        resolve(self.data)
      });
    } else {
      setTimeout(() => {
        reject(self.data);
      });
    }

  }

  Promise.prototype.catch = function (onRejected) {
    Promise.prototype.then(undefined, onRejected);
  }

  //Promise函數(shù)對象方法
  Promise.resolve = function (value) {
    //返回一個狀態(tài)結(jié)果為 成功或失敗的promise對象
    return new Promise((resolve, reject) => {
      if (value instanceof Promise) {
        value.then(resolve, reject);
      } else {
        resolve(value);
      }
    })
  }

  Promise.reject = function (reason) {
    //返回一個狀態(tài)結(jié)果為失敗的promise對象
    return new Promise((resolve, reject) => {
      reject(reason);
    })
  }

  Promise.all = function (promises) {
    //保存所有成功的value的數(shù)組
    const values = new Array(promises.length);
    //記錄成功promise的數(shù)量
    let resloveCount = 0;
    return new Promise((reslove, reject) => {
      promises.forEach((p, index) => {
        p.then(
          value => {
            resloveCount++;
            values[index] = value;
            if (resloveCount === promises.length) {
              reslove(values);
            }
          },
          reason => {
            reject(reason);
          }
        )
      });
    });
  }

  Promise.race = function (promises) {
    return new Promise((resove, reject) => {
      promises.forEach((p, index) => {
        p.then(
          value => {
            resove(value);
          },
          reason => {
            reject(reason);
          }
        )
      });
    });
  }

  //向外暴露Promise的構(gòu)造函數(shù)
  window.Promise = Promise;
})(window)
  • 類Class對象,代碼如下:
//自定義Promise函數(shù)模塊
(function (window) {

  const PENDING = 'pending';
  const RESOLVED = 'resolved';
  const REJECTED = 'rejected';

  class Promise {
    constructor(excutor) {
      //Promise的構(gòu)造函數(shù)
      const self = this;
      //promise狀態(tài) 初始化為pending
      self.status = PENDING;
      //promise異步操作的結(jié)果數(shù)據(jù)
      self.data = undefined;
      //promise的回調(diào)函數(shù)
      self.callbacks = [];

      function resolve(value) {
        if (self.status !== PENDING) {
          return;
        }
        //將狀態(tài)改成resolved
        self.status = RESOLVED;
        self.data = value;
        //若存在callback回調(diào)函數(shù),則立即異步執(zhí)行回調(diào)函數(shù)
        if (self.callbacks.length > 0) {
          setTimeout(() => {
            self.callbacks.forEach(element => {
              element.onResolved(value);
            });
          });
        }
      }

      function reject(reason) {
        if (self.status !== PENDING) {
          return;
        }
        self.status = REJECTED;
        self.data = reason;
        if (self.callbacks.length > 0) {
          setTimeout(() => {
            self.callbacks.forEach(element => {
              element.onRejected(reason);
            });
          });
        }
      }

      try {
        excutor(resolve, reject);
      } catch (error) {
        //捕獲異常了 執(zhí)行reject方法 狀態(tài)成為rejected
        reject(error);
      }
    }
    //Promise原型上的函數(shù)方法
    then(onResolved, onRejected) {
      //當(dāng)前promise對象
      const self = this;

      onResolved = typeof onResolved === 'function' ? onResolved : value => value;
      onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };

      //返回一個新的promise對象
      return new Promise((resolve, reject) => {
        //處理函數(shù)
        function handle(callback) {
          //新promise對象的狀態(tài)結(jié)果 由當(dāng)前promise對象的狀態(tài)結(jié)果決定
          //1.當(dāng)前promise結(jié)果為拋出異常,則新的promise結(jié)果為失敗,值為異常error
          //2.當(dāng)前promise結(jié)果為非promise,則新的promise結(jié)果為成功,值為異常value
          //3.當(dāng)前promise結(jié)果為promise,則新的promise結(jié)果為promise的結(jié)果
          try {
            const result = callback(self.data);
            if (result instanceof Promise) {
              result.then(resolve, reject);
            } else {
              resolve(result);
            }
          } catch (error) {
            reject(error);
          }
        }

        if (this.status === RESOLVED) {
          //立即異步執(zhí)行 當(dāng)前promise對象 成功的回調(diào)函數(shù)
          setTimeout(() => {
            handle(onResolved);
          });
        } else if (self.status === REJECTED) {
          setTimeout(() => {
            handle(onRejected);
          });
        } else {
          //將成功和失敗的回調(diào)函數(shù)保存到callbacks容器中
          self.callbacks.push({
            onResolved(value) {
              handle(onResolved);
            },
            onRejected(reason) {
              handle(onRejected);
            }
          });
        }
      });

      if (self.status === PENDING) {
        //保存回調(diào)方法 到一個對象中
        self.callbacks.push({
          onResolved,
          onRejected
        })
      } else if (self.status === RESOLVED) {
        setTimeout(() => {
          resolve(self.data)
        });
      } else {
        setTimeout(() => {
          reject(self.data);
        });
      }

    }

    catch(onRejected) {
      Promise.prototype.then(undefined, onRejected);
    }

    //Promise函數(shù)對象方法
    static resolve(value) {
      //返回一個狀態(tài)結(jié)果為 成功或失敗的promise對象
      return new Promise((resolve, reject) => {
        if (value instanceof Promise) {
          value.then(resolve, reject);
        } else {
          resolve(value);
        }
      })
    }

    static reject(reason) {
      //返回一個狀態(tài)結(jié)果為失敗的promise對象
      return new Promise((resolve, reject) => {
        reject(reason);
      })
    }

    static all(promises) {
      //保存所有成功的value的數(shù)組
      const values = new Array(promises.length);
      //記錄成功promise的數(shù)量
      let resloveCount = 0;
      return new Promise((reslove, reject) => {
        promises.forEach((p, index) => {
          p.then(
            value => {
              resloveCount++;
              values[index] = value;
              if (resloveCount === promises.length) {
                reslove(values);
              }
            },
            reason => {
              reject(reason);
            }
          )
        });
      });
    }

    static race(promises) {
      return new Promise((resove, reject) => {
        promises.forEach((p, index) => {
          p.then(
            value => {
              resove(value);
            },
            reason => {
              reject(reason);
            }
          )
        });
      });
    }
  }
  //向外暴露Promise的構(gòu)造函數(shù)
  window.Promise = Promise;
}
)(window)

async與await

  • async 函數(shù):函數(shù)的返回值是promise對象,promise對象的狀態(tài)結(jié)果由async函數(shù)執(zhí)行的返回值決定;
  <script>

    async function test() {
      // return 1;
      throw 2;
      // return Promise.resolve(3);
    }

    //返回結(jié)果為promise對象
    const result = test();
    result.then(
      value => {
        console.log('onResolved()',value);
      },
      reason => {
        console.log('onRejected()',reason);
      }
    );

  </script>
  • await 表達式:一般情況下await右側(cè)的表達式為promise對象,也可以是其他的值;‘
    • 若表達式是promise對象,await返回的是promise成功的值;
    • 若表達式是其他值,直接將此值作為await的返回值;
  • 注意事項:
    • await必須寫在async函數(shù)中,但async函數(shù)中可以沒有await;
    • 如果await的promise失敗了,就會拋出異常,需要通過try...catch來捕獲處理;
  <script>

    function test2() {
      return new Promise((reslove, reject) => {
        setTimeout(() => {
          // reslove(5);
          reject(6);
        }, 1000);
      })
    }

    async function test3() {
      try {
        //表達式是promise對象,await返回的是promise成功的值
        const value = await test2();
        console.log(value);
      } catch (error) {
        //await的promise失敗了,就會拋出異常,需要通過try...catch來捕獲處理
        console.log('得到失敗的結(jié)果', error);
      }

      //表達式是其他值,直接將此值作為await的返回值
      const value = test4();
      console.log(value);
    }

    function test4() {
      return 6;
    }

    test3();

  </script>

異步執(zhí)行的宏隊列與微隊列

  • 在JS中 存儲 待執(zhí)行回調(diào)函數(shù)的 隊列 有兩種特定的隊列,分別為宏隊列和微隊列;
  • 宏隊列:用來保存待執(zhí)行的宏任務(wù)回調(diào)函數(shù),例如定時器回調(diào),DOM事件回調(diào),ajax回調(diào);
  • 微隊列:用來保存待執(zhí)行的微任務(wù)回調(diào)函數(shù),例如Promise回調(diào),MutationObserver回調(diào);
  • JS執(zhí)行時會區(qū)分 這兩個隊列;
    • JS引擎首先必須先執(zhí)行完所有的初始化同步任務(wù)代碼;
    • 每次準(zhǔn)備取出第一個宏任務(wù)執(zhí)行前,都要將所有微任務(wù)一個一個取出來執(zhí)行;
  <script>

    setTimeout(() => {
      //回調(diào)函數(shù) 放入宏隊列
      console.log('timeout callback1()');
      Promise.resolve(3).then(
        value => {
          //回調(diào)函數(shù) 放入微隊列
          console.log('Promise onResolved3()', value);
        }
      )
    }, 0);

    setTimeout(() => {
      //回調(diào)函數(shù) 放入宏隊列
      console.log('timeout callback2()');
    }, 0);

    Promise.resolve(1).then(
      value => {
        //回調(diào)函數(shù) 放入微隊列
        console.log('Promise onResolved1()', value);
      }
    )
    Promise.resolve(2).then(
      value => {
        //回調(diào)函數(shù) 放入微隊列
        console.log('Promise onResolved2()', value);
      }
    )

  </script>
image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容