1. 程式人生 > >你是否也在學習ES6 Promise時遇到過這個問題?

你是否也在學習ES6 Promise時遇到過這個問題?

spa ren 是我 相關 eject 日誌 關於 9.png window

背景

周末閑來無事,隨便翻看了一下阮一峰老師的《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 入門》就夠了,好了,就到這裏吧,祝大家周末愉快!!

你是否也在學習ES6 Promise時遇到過這個問題?