背景
周末閑來無事,隨便翻看了一下阮一峰老師的《ES6 標准入門》第2版,ps:之前在阮一峰老師的官網看過電子版,感覺干貨滿滿,所以就買了紙質版;當看到第16章第4節 'Promise.prototype.catch()'時,遇到了一個小困惑,下面我們來一起看一下
開胃湯
首先,Promise.prototype.catch方法是用來'捕獲Promise回調函數中自然發生或主動拋出的錯誤',何為自然發生?何為主動拋出?
自然發生的錯誤:
1 function a() { 2 var x = 1; 3 console.log(x+y) 4 } 5 6 a() // 'ReferenceError: y is not defined'
變量y未定義,所以運行時產生了錯誤,這就是自然發生的錯誤,我們沒有做異常處理,即try catch
主動拋出的錯誤:
1 function a() { 2 var x = 1; 3 try{ 4 console.log(x+y) 5 }catch(err){ 6 console.log(err) 7 } 8 } 9 10 a() // 'ReferenceError: y is not defined'
意識到可能會有異常出現,我們就用try catch處理,那我們如何區分一個錯誤是否被捕獲到了呢?很簡單,就是看瀏覽器控制台的日志:
未捕獲到的錯誤日志是紅色的
捕獲到的錯誤日志是黑色的
正餐
上面已經說了Promise.prototype.catch的作用,以及錯誤的相關知識,那么我究竟遇到了什么問題呢?咱們繼續往下看
書上有這么一個示例:
1 var promise = new Promise(function(resolve, reject){ 2 throw new Error('test') 3 }) 4 promise.catch(function(error){ 5 console.log(error) 6 }) 7 // Error: test
那我們就手動實踐一下吧
錯誤真的被捕獲到了,歐耶,perfect!!突然我又想到Promise不是用來實現異步操作的嗎?那我們就試試ajax吧,然后又意識到沒有接口(主要是當時懶得找),那就用SetTimeout代替吧
代碼:
1 new Promise(function (resolve, reject) { 2 3 // 異步方式拋出異常 4 setTimeout(function () { 5 throw new Error('出錯1') 6 },2000) 7 8 // 同步方式拋出異常 9 throw new Error('出錯2') 10 }).catch(function (err) { 11 console.log(err) 12 })
運行截圖:
納尼?!錯誤1沒有被捕獲?開玩笑呢,讓我緩一緩,終於想到了:setTimeout是在Window下執行的,記得不?上面的代碼就相當於:
1 var clock = function () { 2 setTimeout(function () { 3 throw new Error('出錯1') 4 }) 5 } 6 7 new Promise(function (resolve, reject) { 8 9 // 異步方式拋出異常 10 clock() 11 12 // 同步方式拋出異常 13 throw new Error('出錯2') 14 }).catch(function (err) { 15 console.log(err) 16 })
當我們執行一個函數時,歸根到底就是把函數體內代碼拿到它被調用的地方執行;所以在上上個示例中,在Promise實例中只是啟動了setTimeout定時器,之后定時器就和Promise實例完全沒有關系了,因為它被交由Window對象了,所以定時器中拋出的異常沒有想我們想象的被Promise示例捕獲,而是未加處理,直接在控制台報錯;怎么樣?你是否已經理解,如果理解了,我們再鞏固一下,看看下面的代碼:
1 var clock = function () { 2 setTimeout(function () { 3 console.log(this === window) 4 throw new Error('出錯1') 5 }) 6 } 7 8 var func = function () { 9 throw new Error('出錯3') 10 } 11 12 13 new Promise(function (resolve, reject) { 14 // 異步方式拋出異常 15 clock() 16 17 // 執行window.func拋出異常 18 func() 19 20 // 同步方式拋出異常 21 throw new Error('出錯2') 22 }).catch(function (err) { 23 console.log(err) 24 })
這里錯誤3能不能被catch捕獲呢?答案是:Yes
不要被迷惑呦!雖然func是在Promise示例外面定義的,但是它和錯誤2是拋出方式沒兩樣兒
結語
這就是我在學習Promise相關知識時遇到的一個小插曲,我不相信只有我一個人有這個經歷,哈哈;關於Promise的其他知識這里不是沒有介紹,而是絲毫沒有介紹,不好意思,我又調皮了,主要是我覺得學習ES6,看阮一峰老師的《ECMAScript 6 入門》就夠了,好了,就到這里吧,祝大家周末愉快!!