本人前端小白,項(xiàng)目經(jīng)歷較少旋圆,遇到頁面接口請求較多時(shí)總會有些疑惑宠默,不知道怎么處理合理×榍桑看之前的項(xiàng)目代碼,寫了不知多少回調(diào)抹沪,最近整理promise.all和async/await兩個(gè)方法刻肄,分享一下。同時(shí)結(jié)合兩者優(yōu)化下接口性能融欧,減少請求耗時(shí)敏弃。
Promise
眾所周知,Promise 是一個(gè)對象噪馏,用于表示一個(gè)異步操作的最終完成 (或失敗), 及其結(jié)果值麦到。
語法:new Promise( (resolve, reject) => {...} /* executor */ );
let promise = new Promise((resolve,reject) => {
resolve('success')
// or
reject('error')
})
該對象接收兩個(gè)參數(shù)
- resolve: 將Promise對象的狀態(tài)從“未完成”變?yōu)椤俺晒Α保磸?pending 變?yōu)?resolved)绿饵,在異步操作成功時(shí)調(diào)用,并將異步操作的結(jié)果瓶颠,作為參數(shù)傳遞出去.
- reject: 將Promise對象的狀態(tài)從“未完成”變?yōu)椤笆 保磸?pending 變?yōu)?rejected)拟赊,在異步操作失敗時(shí)調(diào)用,并將異步操作報(bào)出的錯(cuò)誤粹淋,作為參數(shù)傳遞出去吸祟。
promise.then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
then方法會返回一個(gè)Promise,接收一個(gè)回調(diào)函數(shù)作參數(shù),回調(diào)函數(shù)接受Promise對象傳出的值作為參數(shù)桃移。
Promise.all()
將多個(gè)promise實(shí)例包裝成一個(gè)新的promise實(shí)例屋匕,接收一個(gè)數(shù)組作參數(shù)。成功時(shí)返回一個(gè)數(shù)組借杰,數(shù)組中包括所有子promise的結(jié)果过吻;失敗時(shí),返回第一個(gè)失敗promise的結(jié)果蔗衡。
let p1 = new Promise((resolve,reject) => {
resolve('success1')
//reject('error')
})
let p2 = new Promise((resolve,reject) => {
resolve('success2')
})
let p3 = new Promise((resolve,reject) => {
reject('error')
})
成功狀態(tài)時(shí):
Promise.all([p1,p2]).then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
// 返回結(jié)果
['success1', 'success2' ]
失敗時(shí):
Promise.all([p1,p2,p3]).then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
// 輸出
error
注意:
- 成功時(shí)返回?cái)?shù)組中疮装,值的順序跟傳入?yún)?shù)中promise實(shí)例的順序?qū)?yīng),類似于同步執(zhí)行粘都,不會因?yàn)榉祷亟Y(jié)果耗時(shí)的影響廓推。
適用場景:
- 頁面請求過多時(shí),可根據(jù)Promise.all()返回結(jié)果判斷所有請求是否成功翩隧,否則使頁面一直處于loading狀態(tài)樊展,避免用戶操作,或者提是錯(cuò)誤堆生。
- 發(fā)送多個(gè)請求专缠,需要根據(jù)請求順序獲取和使用數(shù)據(jù)的場景。
- 避免promise使用不合理或各種回調(diào)函數(shù)造成地獄回調(diào)淑仆,無法維護(hù)涝婉。
Promise.race()
用法同Promise.all(),哪個(gè)子promise結(jié)果先被返回,就返回該結(jié)果蔗怠,不管是成功還是失敗狀態(tài)墩弯。
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
},1000)
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('error')
}, 500)
})
Promise.race([p1, p2]).then((result) => {
console.log(result)
}).catch((error) => {
console.log(error) // 'error'
})
async/await
- 見名知意: 異步與等待
- 同步思維解決異步問題的方案。
async
函數(shù)使用async后將轉(zhuǎn)換成Promise寞射,并且其返回值也是一個(gè)Promise渔工。
async function fn() {
console.log('async')
return 1
}
fn()
// 結(jié)果
async
Promise {<resolved>: 1}
如果函數(shù)內(nèi)部未使用return,resolved的值為undefind。(最好在瀏覽器上嘗試桥温,node上有返回promise引矩,但無法顯示,可能我的node4版本較低)
- 既然返回值是Promise,那我們變可以使用then()獲取旺韭。
async function fn() {
console.log('async')
return 1
}
fn().then(res => {
console.log(res) // 1
})
await
- await只能在async函數(shù)內(nèi)部使用,用在普通函數(shù)里就會報(bào)錯(cuò)
結(jié)合實(shí)際開發(fā)來說明
fetch('https://blog.csdn.net/')
.then(res => {
console.log(res)
return fetch('https://juejin.im/')
})
.then(res => {
console.log(res)
})
.catch(error => {
console.log(error)
})
- 這種代碼可能大家都有見過氛谜,雖然能體現(xiàn)等待的效果,但當(dāng)鏈?zhǔn)秸{(diào)用過多区端,將充斥著多個(gè)then,配合業(yè)務(wù)邏輯那就部那么語義化值漫,且難以維護(hù)。
async function foo () {
try {
let response1 = await fetch('https://blog.csdn.net/')
console.log(response1)
let response2 = await fetch('https://juejin.im/')
console.log(response2)
} catch (err) {
console.error(err)
}
}
foo()
- 上面代碼,整個(gè)異步處理的邏輯都是使用同步代碼的方式來實(shí)現(xiàn)的,感覺就在寫同步代碼珊燎,比較符合人的線性思維的惭嚣。
- await 后面一定是Promise 對象,如果不是會自動(dòng)包裝成Promise對象悔政。
promise.all與async/await結(jié)合晚吞,優(yōu)化請求
先看個(gè)栗子
function fn1() {
return new Promise(resolve => {
setTimeout(() => {
resolve('p1')
},1000)
})
}
function fn2() {
return new Promise(resolve => {
setTimeout(() => {
resolve('p2')
},2000)
})
}
async function fn() {
let p1 = await fn1()
let p2 = await fn2()
}
fn()
忽略瀏覽器引擎的耗時(shí),fn1谋国,fn2理想總共耗時(shí)3000毫秒
function fn1() {
return new Promise(resolve => {
setTimeout(() => {
resolve('p1')
},1000)
})
}
function fn2() {
return new Promise(resolve => {
setTimeout(() => {
resolve('p2')
},2000)
})
}
async function fn() {
let [res1, res2] = await Promise.all([test1(), test2()])
}
fn()
而這種寫發(fā)理想耗時(shí)2000ms,因?yàn)閜romise.all是將多個(gè)異步操作并行實(shí)現(xiàn)槽地。
需要注意的是,多個(gè)await命令不存在依賴關(guān)系芦瘾。