符合PromiseA+規範並不代表與瀏覽器表現一致

binbin愛學習發表於2019-01-04

引出問題

不處理reject,瀏覽器會拋異常嗎?

考慮下列程式碼的執行情況

new Promise(function(resolve, reject) {
    reject('reason')
})
複製程式碼

很多同學估計都會去Chrome的控制檯輸出一下,發現這段程式碼其實會往外拋一個異常

符合PromiseA+規範並不代表與瀏覽器表現一致

但是參考一個通過Promise/A+規範測試的Promise的原始碼,發現其reject並沒有往外丟擲異常

function reject(reason) {
    if (self.status === 'pending') {
    // 改變狀態
      self.status = 'rejected'
    //   保持值
      self.data = reason
    //   執行回撥
      for(var i = 0; i < self.onRejectedCallback.length; i++) {
        self.onRejectedCallback[i](reason)
      }
    }
  }
複製程式碼

參考文章: 剖析Promise內部結構,一步一步實現一個完整的、能通過所有Test case的Promise類(目前大部按照PromiseA+規範實現Promise的文章,程式碼基本都是這樣的,其中這篇講解比較詳細,具有代表性)

查閱了一下PromiseA+的規範,其實並沒有規定reject要向外丟擲錯誤

各個引擎中的表現

  • Nodejs
    Nodejs和Chrome一樣,也是基於v8的JS引擎。所以首先看看再Nodejs下的表現

    符合PromiseA+規範並不代表與瀏覽器表現一致

  • Edge
    沒拋異常,且IE看不到Promise的狀態

    符合PromiseA+規範並不代表與瀏覽器表現一致

  • Firefox

    符合PromiseA+規範並不代表與瀏覽器表現一致

為什麼

promise-polyfill庫中找到了這樣的方法

符合PromiseA+規範並不代表與瀏覽器表現一致

大意就是,在reject裡面會執行Promise._unhandledRejectionFn方法,由使用者自己決定怎麼處理這個reject的異常。顯然大多數瀏覽器原生Promise的選擇是,如果沒有catch進行處理,就丟擲

總結

  1. 其實,一般情況下,規範的使用catch就不會有上述問題了。在reject的情況下,只要後面有catch處理,就不會丟擲異常。沒有catch的情況下,一般會往外拋異常
  2. 在then的回撥函式中,如果出現了異常且後面沒有catch,還是會向外丟擲異常,所以合理使用catch是很重要的
  3. 最後,並不是說講解Promise實現的文章不好,而是PromiseA+沒有明確指出上述情況,所以希望讀者能夠了解到瀏覽器上的表現差異。

相關文章