咱們都知道,ES是單線程語言。因此異步編程對它來講,尤爲重要。也能夠說是他的核心功能。javascript
咱們常見的異步編程有不少,好比 回調函數
、事件監聽
發佈訂閱
Promise
等。java
在早期的時候,咱們使用的主要方式是回調函數,可是當咱們有不少回調函數須要依賴的時候,一層套一層,就會造成回調地獄
。編程
回調地獄既不利於閱讀也不利於維護,因此前輩先賢們爲了解決這個問題,作了不少努力。其中Promise 就是其中的一種方案。promise
Promise
是一個構造函數,返回一個 promise
對象。該對象有三種狀態,並且狀態不可逆。還有then
catch
finally
等方法。網上有大量的基礎方法定義,咱們就不在羅列了。異步
咱們知道,Promise支持鏈式調用,那假如中間狀態變成rejected了,會怎麼樣呢。異步編程
let p1 = new Promise((resolve,reject) => {
setTimeout( () => resolve(200) , 1000)
})
p1.then(() => {
console.log(11)
})
.then(() => {
throw Error(22)
})
.then( () => {
console.log(33)
})
.catch(err => {
console.log('this is error',err)
})
// 11
// this is error 22
複製代碼
當 then
的回調函數返回一個錯誤的時候,返回的是一個rejected`狀態的promise。以後的鏈式調用被終止了,被最後的catch捕獲到。函數
咱們知道then
實際上是能夠接受兩個回調函數的,咱們換一個方式猜下執行順序是什麼呢?post
let p1 = new Promise((resolve,reject) => {
setTimeout( () => resolve(200) , 1000)
})
p1.then(() => {
console.log(11)
})
.then(() => {
throw Error(22)
})
.then( () => {
console.log(33)
},fail => {
console.log('this is from 3rd fn',fail)
})
.catch(err => {
console.log('this is error',err)
})
// 輸出結果爲:
//11
// this is from 3rd fn
複製代碼
有沒有想到這個結果。ui
從現象看:是由於前面已經處理了rejected 因此後面catch不會在處理了。this
let p1 = new Promise((resolve,reject) => {
setTimeout( () => resolve(200) , 1000)
})
p1.then(() => {
console.log(11)
})
.then(() => {
throw Error(22)
})
.then( () => {
console.log(33)
},fail => {
console.log('this is from 3rd fn', fail)
})
.then( () => {
console.log(44)
})
.catch(err => {
console.log('this is error',err)
})
.then( () => {
console.log(55)
})
// 輸出爲:
// 11
// this is from 3rd fn 22
// 44
// 55
複製代碼
怎麼樣,有沒有想到,處理錯誤以後,還能繼續執行,哪怕在catch後面也能執行。
透過現象看本質,下面咱們對上面幾種狀況用一個統一的解釋來理解下。
首先咱們要知道 then
方法,他接受兩個回調,一個處理 fulilled
狀態, 一個處理 rejected
狀態。每次都返回一個新的promise 對象。
catch的本質是obj.then(undefined, onRejected)
。
因此上面的幾種狀況也就好理解了:
then 和 catch 都會返回一個promise 對象。當中間有狀態變爲rejected以後,他會一直往下尋找,找到最近的rejected狀態處理函數,以後根據處理函數的返回值繼續返回不一樣狀態的promise對象。一直執行到鏈式調用的最後。
因此咱們在使用的時候要注意了,避免沒必要要的麻煩。通常用catch 來處理,而且放到最後。這樣能統一處理。
let p1 = new Promise((resolve, reject) => {
console.log(11)
resolve()
console.log(22)
})
p1.then(() => {
console.log(33)
})
console.log(44)
// 結果爲: 11 、22 、4四、33
複製代碼
解釋:Promise構造函數會當即執行,因此先是十一、resolve、22,因爲then是異步的,因此代碼緊接着是4四、最後纔是33
Promise.resolve(11)
.then(22)
.then(Promise.resolve(33))
.then(console.log)
// 輸出 11
複製代碼
解釋:then 參數不是function的時候都會被忽略。
下面咱們來看一下,它的一些經常使用場景:
// 異步請求b 依賴異步請求a
let p1 = new Promise(function(resolve,reject){
$.post(urla,data,function(res){
resolve(res);
})
})
p1.then(function(res){
$.post(urlb,data,function(){
// 處理請求返回後的數據
})
})
複製代碼
咱們有時候常常會遇到這樣的一種場景,咱們須要發起兩個互不依賴異步請求,而後等待兩個請求都返回以後再處理。
let p1 = new Promise((resolve,reject) =>{
setTimeout( () => resolve(100), 200)
})
let p2 = new Promise((resolve,reject) =>{
setTimeout( () => reject(200), 300)
})
Promise.all([p1,p2])
.then(values =>{
console.log(values); // [100,200]
},fail => {
console.log(fail)
})
複製代碼
all
方法返回的是一個promise
對象,因此他也有 then
catch
等方法。
但願上面一點點內容,可以幫助你們加深理解。若有錯誤,不吝指正。
參考連接: