前端基本功(一):不能不瞭解的Promise

promise: 異步編程的解決方案(一)
一. promise是什麼
  1. 從這個單詞語義上能夠得知:這是一個承諾。承諾以一種優雅的方式處理咱們的異步操做的回調函數帶來的一系列的問題(調用時序、異常捕獲等)。目前基於promise實現的API與類庫也是不少的,而且普遍被你們使用(fetch、axios、oss sdk等)。javascript

  2. 曾幾什麼時候,咱們在傳統前端開發技術中,常用callback的方式來解決咱們在處理異步數據請求,當業務場景過於複雜時,常常就會寫出callback中再callback的代碼,也就是你們常說的又臭又長的回調地獄。使用咱們的promise方式處理,就能夠優雅解決咱們的問題。前端

  3. 咱們能夠在控制檯打印一下咱們的Promise對象。能夠看到Promise是一個構造函數,在它的原型上擁有then、catch、finally等方法,自身擁有all、race、reject、resolve等方法。java

promise-img

2、 Promises/A+ 規範

ES6 中的 promise 實現是基於 Promises/A+ 規範。主要是對promise的狀態、thenable對象、執行過程等進行規範。ios

  1. 狀態:promise是一個擁有狀態的對象,而且它的狀態必須等待中(Pending)執行成功(Fulfilled)執行失敗(Rejected)這三種中的一種。promsie狀態 只能由 pending => fulfilled/rejected, 一旦修改就不能再變。
  2. thenable對象:擁有then方法的對象就是thenable對象,只要是promise就必需要會有then方法,then方法接受兩個可選參數:onFulfilledonRejected。這兩個參數通常來講都是函數,若是傳入的不是函數將會被忽略。onFulfilled回調函數是在promise對象的狀態變爲resolved時調用,onRejected回調函數是在promise對象的狀態變爲rejected時調用。then方法贊成也必須返回一個promise對象,這樣就造成了鏈式調用。
3、API方法
  1. 靜態方法git

    1. Promise.resolve 返回一個fulfillled狀態的promise對象。Promise.reject返回一個rejected狀態的promise對象。能夠認爲是new Promise()的快捷方式。github

      Promise.reslove('hahaha');
      // 至關於
      new Promise((relove, reject) => {
        reslove('hahahha');
      })
      
      Promise.reject('hahaha');
      // 至關於
      new Promise((relove, reject) => {
        reject('hahahha');
      })
      複製代碼
    2. Promise.all 接收一個promise對象數組爲參數: 多個promise任務同時執行,若是所有成功執行,則以數組的方式返回全部 Promise 任務的執行結果。 若是有一個 Promise 任務 rejected,則只返回 rejected 任務的結果。編程

      const promise1 = new Promise((reslove, reject) => {
      	reslove(1);
      })
      const promise2 = new Promise((reslove, reject) => {
      	reslove(2);
      })
      const promise3 = new Promise((reslove, reject) => {
      	reject(3);
      })
      
      Promise.all([promise1, promise2]).then(data => {
        console.log('data', data); //  [1, 2]
      }, err => {
        console.log('err', err);
      })
      
      Promise.all([promise1, promise2, promise3]).then(data => {
        console.log('data', data);
      }, err => {
        console.log('err', err); // err 3
      })
      複製代碼
    3. Promise.race接收一個promise對象數組爲參數: 只要有一個promise對象進入 FulFilled 或者 Rejected 狀態的話,就會繼續進行後面的處理。json

      // 以前有遇到給fetch設置timeout time的需求: 思路就是咱們先定義超時promise,當咱們的定時器在必定time後這個promise對象 reject. 將咱們的請求方法與這個timeoutPromise同時放入Promise.race中就能夠達到timeout的效果。
      
       const timeoutPromise = new Promise((resolve, reject) => {
          setTimeout(
            () => reject(new RequestException('網絡超時', '當前網絡環境不穩定,請稍後再試。')),
            timeout,
          );
        })
       
       Promise.race([fetchPromise, timeoutPromise]).then(data => ....);
      複製代碼
  2. promise對象方法axios

    1. Promise.prototype.then方法:then方法接受兩個可選參數:onFulfilledonRejectedthen方法是異步執行的.
    // onFulfilled 是用來接收promise成功的值
    // onRejected 是用來接收promise失敗的緣由
    promise.then(onFulfilled, onRejected);
    複製代碼
    1. Promise.prototype.catch方法:在鏈式寫法中能夠捕獲前面then中發送的異常。
    // 注意
    // onRejected 不能捕獲當前onFulfilled中的異常
    promise.then(onFulfilled, onRrejected); 
    
    // 能夠寫成:
    promise.then(onFulfilled)
           .catch(onRrejected);  
    複製代碼
    1. Promise.prototype.finally方法:無論 Promise 對象最後狀態如何,都會執行的操做。(再也不ES6中,ES2018引入標準)數組

      // 無論promise最後的狀態,在執行完then或catch指定的回調函數之後,都會執行finally方法指定的回調函數。finally方法的回調函數不接受任何參數,這意味着沒有辦法知道,前面的 Promise 狀態究竟是fulfilled仍是rejected。這代表,finally方法裏面的操做,應該是與狀態無關的,不依賴於 Promise 的執行結果。
      promise
      .then(result => {···})
      .catch(error => {···})
      .finally(() => {···});
      複製代碼
    2. Promise.prototype.done方法:注意此方法並不在ES6以及Promise A+規範中規定以及實現。(可是不少第三方庫提供了此方法的實現)

      if (typeof Promise.prototype.done === 'undefined') {
          Promise.prototype.done = function (onFulfilled, onRejected) {
              this.then(onFulfilled, onRejected).catch(function (error) {
                  setTimeout(function () {
                      throw error;
                  }, 0);
              });
          };
      }
      var promise = Promise.resolve();
      promise.done(function () {
          JSON.parse('this is not json');    // => SyntaxError: JSON.parse
      });
      
      // done 對比 then
      // 1. then方法並不會捕獲當前onFulfilled中的錯誤,必須後面再跟catch。done中發生的異常直接拋出。
      // 2. done以後不會反悔promise對象,就是done以後不能使用catch等方法組成方法鏈。
      複製代碼

4、微任務(參考:javascript的運行機制

new Promise((resolve, reject) => {
  resolve(1);
}).then(data => console.log(data));
console.log(2);

// 上面的代碼是先輸出2, 再輸出1.
// Promise當即執行,then函數分發到微任務Event Queue,Node.js中的process.nextTick一樣也是分發到微任務Event Queue。
// Promise 的回調函數不是正常的異步任務,而是微任務(microtask)。宏任務必然是在微任務以後才執行的(由於微任務其實是宏任務的其中一個步驟)。
// tip: process.nextTick()的意思就是定義出一個動做,而且讓這個動做在下一個事件輪詢的時間點上執行。
複製代碼
相關文章
相關標籤/搜索