答疑解惑 -- Promise

Promise

本章主要是解釋幾個大部分人關於promise疑惑的地方,或者可能跟你想象不太一樣的地方,所以需要對promise有一定的基礎才行,最好在項目裏用過。
在開始之前,先跟大家確認一個概念:決議。決議就是promise的判定。比如執行reslove()或者reject(),這個promsie就被判定成一個狀態了,或者說被決議了

promise 語法格式

在語法格式方面,好像我們都知道,也經常用。比如我們最常見的寫法

let promise = new Promise((resolve, reject) => {
   // to do some thing
   console.log(a);
   resolve();
});
promise.then(() => {
   console.log('run success');
})
.catch(() => {
   console.log('run fail');
})

這個格式寫法完全沒有錯。而且很多書上都推薦這麼寫。尤其是鏈式寫法(then-then-catch)。
但promise的格式其實不是這樣的。它應該是下面這樣的。

let promise = new Promise((resolve, reject) => {
   // to do some thing
   console.log(a);
   resolve();
});
promise.then(() => {
   console.log('run success');
}, () => {
   console.log('run fail')
})
.catch(() => {
   console.log('run fail');
})

這個裏面的then裏應該有兩個參數(兩個回調,一個用來接收成功決議,一個接收失敗決議)。只是我們經常把第二個參數省略了,或者說爲了代碼寫起來方便,看起來舒服,我們故意的。
讀到這裏你可以疑惑,這個有什麼的呢,不就是少寫一個回調嘛。這個在寫代碼中確實沒有作用,但是在理解promise裏的某些東西卻是非常重要(下面會舉到這個例子)。這裏可以給你拋出一個問題:爲什麼catch 能夠抓到好幾個then之前報的錯呢?

只一次決議

之前有同事問這個問題:下面的代碼裏爲啥會執行出success, 爲啥不是進入catch裏呢(方法b會拋出異常啊)?您是否知道原因呢?

console.log('here')

new Promise(resolve => {
  resolve()
  console.log('000')
  b()
}).then( value => {
   console.log('success');
})
.catch( error => {
  console.log('Erro123r', error.message)
})

function b() {
  console.log(999)
  throw new Error('123')
}

這個就是promise一個最重要的特性。一次決議後,就不可更改。所以本題的核心就是在先執行reslove(),再執行b方法,執行reslove決議已經定了,b的報錯已經無法改不決議的結果了。所以它只能走then,而不走catch。如果我們想要進入catch,只需要b方法執行放到resolve前面,錯誤先讓promise進行決議。
promise 只決議一次纔是我們放心大膽的用的保證,否者我們都得考慮它此時決議結果是什麼。我可以放心大膽的像下面這麼寫:可以寫好多個then,而不用擔心決議改不了,then 不會執行。

function bar() {
 // to do something
}
function foo() {
 // to do something
}
let p = new Promise((resolve, reject) => {
     //  to do something
     resolve();
})
p.then(bar);
p.then(foo);
.
.
.

爲什麼catch 能夠抓到好幾個then之前報的錯呢?

我們先來看看鏈式結構,省略then裏的回調方法。

let p = Promise.resolve();
p.then().then().then().then().catch()

鏈接結構就是這樣吧。看到這個結構就解答了常見的很多人都會理解錯誤的一個誤區(p的決議是reject後,會直接執行catch)。
從這個鏈式結構上看,我們代碼的執行不可能不執行then,或者說跳過前面的then,直接執行catch。我們只能鏈式調用,一個then,一個then的調用。直到調用到最後的catch。此時我們得到一個重要的結論:
then方法不管是決議成功和失敗它都會執行
此時有人會疑惑,如果then都執行的話,then裏回調不就被執行了嗎?
這個就是我們在第一部分介紹promise的格式了。then裏面有兩個參數(成功回調,失敗回調)。一旦決議失敗,then裏的失敗回調就會執行。但是一般情況下,我們不寫失敗回調。promise會自動補充一個失敗回調,同時會把失敗的狀態傳遞給下一個then。一個一個的往下傳遞,只要下面的then都不寫失敗回調,就會一直傳遞下去,直到遇到catch。
這個就是爲什麼catch能夠抓到好幾個then之前報的錯誤。

這些都是我花很多時間學習,同時花了很久時間碼字。希望能夠給大家對理解promise帶來幫助。
clipboard.png

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章