我們都知道,ES是單線程語言印蔗。所以異步編程對它來說扒最,尤其重要。也可以說是他的核心功能华嘹。
我們常見的異步編程有很多吧趣,比如 回調(diào)函數(shù)?
、事件監(jiān)聽
發(fā)布訂閱
Promise
等除呵。
在早期的時候再菊,我們使用的主要方式是回調(diào)函數(shù),但是當我們有很多回調(diào)函數(shù)需要依賴的時候颜曾,一層套一層纠拔,就會形成回調(diào)地獄
。
回調(diào)地獄既不利于閱讀也不利于維護泛豪,所以前輩先賢們?yōu)榱私鉀Q這個問題稠诲,做了很多努力。其中Promise 就是其中的一種方案诡曙。
Promise
Promise
是一個構造函數(shù)臀叙,返回一個promise
對象。該對象有三種狀態(tài)价卤,而且狀態(tài)不可逆劝萤。還有then
catch
finally
等方法。網(wǎng)上有大量的基礎方法定義慎璧,我們就不在羅列了床嫌。
使用
then的鏈式調(diào)用
我們知道,Promise支持鏈式調(diào)用胸私,那假如中間狀態(tài)變成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
的回調(diào)函數(shù)返回一個錯誤的時候岁疼,返回的是一個rejected`狀態(tài)的promise阔涉。之后的鏈式調(diào)用被終止了,被最后的catch捕獲到捷绒。
我們知道then
其實是可以接受兩個回調(diào)函數(shù)的瑰排,我們換一個方式猜下執(zhí)行順序是什么呢?
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
有沒有想到這個結果疙驾。
從現(xiàn)象看:是因為前面已經(jīng)處理了rejected 所以后面catch不會在處理了凶伙。
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
怎么樣,有沒有想到它碎,處理錯誤之后函荣,還能繼續(xù)執(zhí)行显押,哪怕在catch后面也能執(zhí)行。
透過現(xiàn)象看本質(zhì)傻挂,下面我們對上面幾種情況用一個統(tǒng)一的解釋來理解下乘碑。
首先我們要知道
then
方法,他接受兩個回調(diào)金拒,一個處理fulilled
狀態(tài)兽肤, 一個處理rejected
狀態(tài)。每次都返回一個新的promise 對象绪抛。catch的本質(zhì)是
obj.then(undefined, onRejected)
资铡。
所以上面的幾種情況也就好理解了:
then 和 catch 都會返回一個promise 對象。當中間有狀態(tài)變?yōu)閞ejected之后幢码,他會一直往下尋找笤休,找到最近的rejected狀態(tài)處理函數(shù),之后根據(jù)處理函數(shù)的返回值繼續(xù)返回不同狀態(tài)的promise對象症副。一直執(zhí)行到鏈式調(diào)用的最后店雅。
所以我們在使用的時候要注意了,避免不必要的麻煩贞铣。一般用catch 來處理闹啦,并且放到最后。這樣能統(tǒng)一處理辕坝。
幾個常見題型
let p1 = new Promise((resolve, reject) => {
console.log(11)
resolve()
console.log(22)
})
p1.then(() => {
console.log(33)
})
console.log(44)
// 結果為: 11 窍奋、22 、44酱畅、33
解釋:Promise構造函數(shù)會立即執(zhí)行费变,所以先是11、resolve圣贸、22,由于then是異步的扛稽,所以代碼緊接著是44吁峻、最后才是33
Promise.resolve(11)
.then(22)
.then(Promise.resolve(33))
.then(console.log)
// 輸出 11
解釋:then 參數(shù)不是function的時候都會被忽略。
使用場景
下面我們來看一下在张,它的一些常用場景:
1.異步b依賴異步a
// 異步請求b 依賴異步請求a
let p1 = new Promise(function(resolve,reject){
$.post(urla,data,function(res){
resolve(res);
})
})
p1.then(function(res){
$.post(urlb,data,function(){
// 處理請求返回后的數(shù)據(jù)
})
})
2.依賴異步a和異步b
我們有時候經(jīng)常會遇到這樣的一種場景用含,我們需要發(fā)起兩個互不依賴異步請求,然后等待兩個請求都返回之后再處理帮匾。
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
等方法。
希望上面一點點內(nèi)容瘟斜,能夠幫助大家加深理解缸夹。如有錯誤痪寻,不吝指正。
求點贊虽惭,求關注~