本文開始
在一個 Promise chaining 中,如果某一個階段的 promise 呼叫了 reject
,則該 chaining 的處理位置會直接從呼叫 reject 的 promise 那邊,跳到離它最近的的 rejection handler。
上個範例
1 | new Promise((resolve, reject) => { |
由上面的範例就可以看得出來 catch 不需要是接在呼叫 reject 的那個 Promise 後面的第一個鏈結對象,即便中間跨過很多的.then
,但仍然會直接呼叫到離發生地點最近的 catch 。
Implicit try…catch
在 promise executor(new Promise
在寫的) 和 handler function (傳入 .then
的 function) 都會有一個看不見的 try…catch
包裹在它們外圍。
如果有一個 例外情況(exception) 發生了,則它會會被接起來,並自動呼叫 reject 。
先來個範例
1 | new Promise((resolve, reject) => { |
上面的程式碼可以寫成下面這樣,有一樣的效果
1 | new Promise((resolve, reject) => { |
從上面的範例可以看出來,在 executor 周圍的隱形的 try…catch
會自動的把 error 接起來,並將它當為 reject 的值。
上面的範例,都是寫在 executor 裡面拋出錯誤,下面也來寫個由 handler function 拋出錯誤的範例
1 | new Promise((resolve, reject) => { |
除了上面都是拋出錯誤的範例,下面這邊是程式碼撰寫上發生的錯誤,呼叫沒有被定義的 function
1 | new Promise((resolve, reject) => { |
Rethrowing
假設一個 Promise chaining 執行的流程,因為遇到 throw
而進入到某個 .catch
,
此時,這個 chaining 執行的流程將會取決於這個 .catch 不同的操作,而執行後續不一樣的路線,
假設
在 .catch
又再 throw
一次,則這個 stream 又會跑到離這個 .catch
最近的下一個 error handler 。
但如果我們在 .catch
執行過後,讓他正常的結束,則它會繼續執行下一個 .then
。
下面的範例是讓 .catch
正常的結束,往後執行其它的 .then
1 | new Promise((resolve, reject) => { |
下面的範例,就是在一個 .catch
裡面再用 throw ,讓 stream 進入到下一個最近的 error handler 中
1 | new Promise((resolve, reject) => { |
上面的範例就會先執行 step 1 ,因為在 step 1 throw 東西出來,所以再進到 step 2 裡面。
Unhandled rejections
如果,Promise 執行的 stream 裡面,有拋出錯誤,但是,沒有任何 error handler 去承接這個錯誤的話,會發生什麼事呢?
像下面這個範例
1 | new Promise((resolve, reject) => { |
上面的範例,當 promise 呼叫了 reject,照理來接下來就要跳到最近的 error handler 來承接,但是,卻沒有這個 error handler,這個時候,error 會 “卡” 住,因為沒有人可以接續後面的處理。
如果,有錯誤發生但沒有被 try…catch
給接起來的話,JS 會卡住並丟出一個訊息到 console 裡,那沒有被接住的 promise rejection 也會發生類似的事情。
JS 其實會追蹤這種沒有被接住的錯誤,並在追蹤到這種狀況發生的時候,丟出一個全域性的錯誤。
並且可以利用 unhandledRejection
這個 function 來監聽這種錯誤的發生,
用法如以下範例
1 | window.addEventListener('unhandledRejection', function (event) { |
以上的範例,加在 unhandledRejection
的 callback function 會傳入一個 event,而這個 event 就會包含觸發這個事件的 error 內容。
而這種沒有錯誤機制去承接錯誤的這種狀況,通常最好的應對方式就是通知使用者發生這種問題了,並且回報此問題給 server。
Conclusion
用 Promise 來做錯誤處理是蠻方便的,因為,我們可以直接將 .catch
接在 Promise chaining 中,它就會接住由前面的發送出來的錯誤 (不管是 reject 傳出來的, throw 出來的 或者 undefined error 都會被接住)。~~
最後,我們會需要使用 unhandledRejection
來替我們處理當有一些沒有做錯誤承接的錯誤發生的時候的處理或通知。