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

引出問題

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

考慮下列代碼的執行狀況git

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

不少同窗估計都會去Chrome的控制檯輸出一下,發現這段代碼其實會往外拋一個異常github

可是參考一個經過Promise/A+規範測試的Promise的源碼,發現其reject並無往外拋出異常npm

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的文章,代碼基本都是這樣的,其中這篇講解比較詳細,具備表明性)promise

查閱了一下PromiseA+的規範,其實並無規定reject要向外拋出錯誤瀏覽器

各個引擎中的表現

  • Nodejs
    Nodejs和Chrome同樣,也是基於v8的JS引擎。因此首先看看再Nodejs下的表現
    函數

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

  • Firefox
    ui

爲何

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

大意就是,在reject裏面會執行Promise._unhandledRejectionFn方法,由用戶本身決定怎麼處理這個reject的異常。顯然大多數瀏覽器原生Promise的選擇是,若是沒有catch進行處理,就拋出code

總結

  1. 其實,通常狀況下,規範的使用catch就不會有上述問題了。在reject的狀況下,只要後面有catch處理,就不會拋出異常。沒有catch的狀況下,通常會往外拋異常
  2. 在then的回調函數中,若是出現了異常且後面沒有catch,仍是會向外拋出異常,因此合理使用catch是很重要的
  3. 最後,並非說講解Promise實現的文章很差,而是PromiseA+沒有明確指出上述狀況,因此但願讀者可以瞭解到瀏覽器上的表現差別。
相關文章
相關標籤/搜索