一、什么是Promise
A
Promiseis an object representing the eventual completion or failure of an asynchronous operation.
從官方文檔我們可知
- Promise是ES6新增的一個對象,一個構造函數(shù)
- 用于多層次異步操作以同步操作的流程表達出來,避免了層層嵌套的回調函數(shù)地獄
1.1 Promise的三種狀態(tài)
- pending: 初始狀態(tài),既不是成功,也不是失敗狀態(tài)。
- fulfilled: 意味著操作成功完成。
- rejected: 意味著操作失敗。
什么意思呢?三種狀態(tài)對應異步操作的三種情況,比如發(fā)送一次ajax請求,初始等待時,狀態(tài)為pending,ajax請求成功時,調用Promise內置函數(shù)resolve(), Promise狀態(tài) => fulfilled,請求失敗時,調用函數(shù)reject(),Promise狀態(tài) => rejected
二、Promise 基本用法
var Promise: PromiseConstructor
new <any>(executor: (resolve: (value?: any) => void, reject: (reason?: any) => void) => void) => Promise<any>
從語法上來看,Promise 是一個構造函數(shù),需要傳入一個參數(shù)executor函數(shù).
new Promise 時會調用executor 函數(shù), executor函數(shù)也有兩個參數(shù).resolve 和 reject,這兩個參數(shù)也是函數(shù),調用resolve或reject時,分別將promise的狀態(tài)改為fulfilled(完成)或rejected(失?。?。Promise 狀態(tài)只能唯一
2.1 Promise基本使用
下面來看兩個例子
(1)
var promise = new Promise((resolve, reject) => {
if(異步請求成功){
resolve()
}else{
reject()
}
})
promise.then(()=>{
//success
},()=>{
//failure
})
(2) 用定時器setTimeout模擬異步請求成功
function ajax() {
return new Promise(resolve => {
setTimeout(resolve, 1000)
})
}
ajax().then(() => {
console.log("request success") //success
})
上面代碼表示,如果異步操作成功,就調用resolve()方法,就會執(zhí)行Promise實例then()方法的第一個回調函數(shù),如果失敗則調用then()方法的第二個回調函數(shù).
2.2 Promise使用時傳參
resolve()和reject()函數(shù)調用時可傳參,傳入的參數(shù)會被Promise實例 then和catch方法捕獲.
var promise = new Promise((resolve, reject) => {
if (異步請求成功) {
resolve("success")
} else {
reject("error")
}
})
promise.then( res => {
res // success
})
//捕獲異??捎胏atch()方法
promise.catch( err => {
err // error
})
2.3 Promise 鏈式調用
Promise強大的地方在于此,如果發(fā)送一個異步請求,又返回另外一個異步請求時,可用鏈式調用
new Promise((resolve) => {
resolve(1)
}).then((res) => {
return new Promise((resolve) => {
resolve(res+2)
})
}).then((res) => {
return new Promise((resolve) => {
resolve(res+3)
})
}).then((res) => {
res // 6
})
當對異步請求返回結果res的操作簡單操作時,可用Promise.resolve()簡寫
new Promise((resolve) => {
resolve(1)
}).then((res) => {
return Promise.resolve(res+2)
}).then((res) => {
return Promise.resolve(res+3)
}).then((res) => {
res // 6
})
還有一種更簡單的語法糖
new Promise((resolve) => {
resolve(1)
}).then((res) => {
return res + 2
}).then((res) => {
return res + 3
}).then((res) => {
res // 6
})
2.4 鏈式調用注意事項
鏈式調用(chaining)按序執(zhí)行,有以下約定,使用時要多注意.
- 在本輪 事件循環(huán)運行完成之前,回調函數(shù)是不會被調用的。
- 即使異步操作已經完成(成功或失?。?,在這之后通過 then()添加的回調函數(shù)也會被調用
- 通過多次調用then() 可以添加多個回調函數(shù),它們會按照插入順序執(zhí)行
看下面的例子
new Promise((resolve) => {
resolve()
}).then(() => {
console.log('execute') // execute
}).then(() => {
console.log('execute') // execute
}).then(() => {
console.log('execute') // execute
})
只要觸發(fā)了一次resolve(),鏈上的所有then都會被調用,當然后面的沒有調用resolve自然拿不到操作數(shù).
new Promise((resolve) => {
resolve()
}).then(() => {
console.log('execute') // execute
}).then(() => {
console.log('execute') // execute
}).catch(()=>{
console.log('execute') // no execute
}).then(()=>{
console.log('execute') // execute
})
中間穿插catch(),其后的then也會被執(zhí)行
new Promise((resolve,reject) => {
reject()
}).then(() => {
console.log('execute') // no execute
}).catch(()=>{
console.log('execute') // execute
}).then(() => {
console.log('execute') // execute
})
new Promise((resolve,reject) => {
reject()
}).then(() => {
console.log('execute') // no execute
}).catch(()=>{
console.log('execute') // execute
}).then(() => {
console.log('execute') // execute
})
捕獲reject()后的then會被執(zhí)行
new Promise((resolve) => {
resolve()
}).then(() => {
console.log("execute") // execute
throw new Error()
}).then(() => {
console.log("execute") // no execute
}).catch(() => {
console.log("execute") // execute
}).then(() => {
console.log("execute") // execute
})
情況有很多種,怎么去理解呢,看下面這個例子
const arr = ["foo","bar"]
arr.forEach(async (item) => {
const res = await new Promise(resolve=>{
resolve("why")
}).then(res=>{
return res
})
console.log(res);
console.log(item);
// why、foo、why、bar
})
res 會拿到 Promise resolve()的操作數(shù)
輸出結果為 why、foo、why、bar
把return res 注釋發(fā)現(xiàn),仍然可以輸出結果,相當于執(zhí)行了 Promise.resolve(),catch()中同理
const arr = ["foo","bar"]
arr.forEach(async (item) => {
const res = await new Promise(resolve=>{
resolve("why")
}).then(res=>{
// return res
// Promise.resolve()
})
console.log(res);
console.log(item);
// undefined、foo、undefined、bar
})
總結 :then(),catch()觸發(fā)后,會返回一個空的 resolve()
三、Promise內置方法
3.1 Promise.all()
Promise.all(iterable) 方法返回一個 Promise 實例,此實例在 iterable迭代器 參數(shù)內所有的 promise 都“完成(resolved)”或參數(shù)中不包含 promise 時回調完成(resolve);如果參數(shù)中 promise 有一個失?。╮ejected),此實例回調失?。╮eject),失敗的原因是第一個失敗 promise 的結果。
var p1 = Promise.resolve("res1")
var p2 = Promise.resolve("res2")
Promise.all([p1, p2]).then((res) => {
res // ["res1", "res2"]
})
捕獲異常結果err為響應速度快的
var p1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("err1")
}, 1000)
})
var p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("err2")
}, 2000)
})
Promise.all([p1, p2]).catch((err) => {
err //err1
})
3.2 Promise.race()
- race 函數(shù)返回一個 Promise,它將與第一個傳遞的 promise 相同的完成方式被完成。它可以是完成( resolves),也可以是失敗(rejects),這要取決于第一個完成的方式是兩個中的哪個。
- 如果傳的迭代是空的,則返回的 promise 將永遠等待。
- 如果迭代包含一個或多個非承諾值和/或已解決/拒絕的承諾,則 Promise.race 將解析為迭代中找到的第一個值。
var p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("res1")
}, 3000)
})
var p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("err2")
}, 2000)
})
Promise.race([p1, p2])
.then((res)=>{
console.log(res);
}).catch((err)=>{
console.log(err); //err2
})
then,catch只會調用二者其一,并且取決于迭代器中參數(shù)的響應速度
3.3 Promise.allSettled()
Promise.allSettled()方法返回一個在所有給定的promise已被決議或被拒絕后決議的promise,并帶有一個對象數(shù)組,每個對象表示對應的promise結果
var p1 = Promise.resolve("res1")
var p2 = Promise.reject("res2")
Promise.allSettled([p1, p2]).then((res) => {
res // [{status: "fulfilled", value: "res1"},
// {status: "rejected", reason: "res2"}]
})
返回一個對象數(shù)組,包含iterator所有參數(shù)Promise的狀態(tài)和結果