說明
該筆記是學(xué)習(xí)了尚硅谷李強老師的Promise課程及結(jié)合阮一峰老師的ES6加上自己的理解整理的??
1,Promise是什么?
1.1Promise的理解
1)抽象表達:Promise是JS中進行異步編程的新的解決方案,主要用來解決回調(diào)地獄的問題,可以有效的減少回調(diào)嵌套,并且異??梢越y(tǒng)一處理,并且支持鏈式編程
2)具體表達:從語法上講Promise是一個構(gòu)造函數(shù),從功能上講Promise對象用來封裝異步操作并獲取其成功/失敗的結(jié)果值
1.2promise的狀態(tài)
對應(yīng)實例對象的屬性promiseState,它有三個值 :
1.pending:未決定「初始值」
2.resolved/fullfilled:成功
3.rejected:失敗
狀態(tài)改變
pending變?yōu)閞esolved. pending變?yōu)閞ejected
說明:只有這 2 種,情況, 且一個 promise 對象只能改變一次 無論變?yōu)閞esolved還是rejected, 都會有一個結(jié)果數(shù)據(jù), 成功的結(jié)果數(shù)據(jù)一般稱為 value, 失敗的結(jié)果數(shù)據(jù)一般稱為 reason
1.3promise的執(zhí)行流程

流程說明:
new Promise((resolve,reject) =>{})
創(chuàng)建Promise實例的時候,構(gòu)造函數(shù)接受一個函數(shù)作為參數(shù),該函數(shù)也有2個參數(shù)resolve()為函數(shù),成功時調(diào)用,改變pending狀態(tài)為resolved,狀態(tài)變?yōu)閞esolved時,then函數(shù)的第一個參數(shù)回調(diào)函數(shù)被調(diào)用
reject()為函數(shù),失敗時調(diào)用,改變pending狀態(tài)為rejected,狀態(tài)變?yōu)閞ejected時,then函數(shù)的第二個參數(shù)回調(diào)函數(shù)被調(diào)用或者catch的回調(diào)函數(shù)被調(diào)用
并且then函數(shù),catch函數(shù)被調(diào)用后返回一個新的promise對象
1.4promise狀態(tài)何時發(fā)生改變?
一共有三種情況可以使promise的狀態(tài)發(fā)生改變
1.resolve被調(diào)用,狀態(tài)變?yōu)閞esolved
2.reject被調(diào)用,狀態(tài)變?yōu)閞ejected
3,throw拋異常,狀態(tài)變?yōu)閞ejected
只有狀態(tài)變成resolved/rejected后,then,catch中的回調(diào)函數(shù)才會被調(diào)用
1.5catch的穿透作用
then(value=>{},reason=>{})then函數(shù)的第二個回調(diào)函數(shù)可以用于處理異常,也可以使用catch統(tǒng)一處理異常
2者的區(qū)別:then的第二個回調(diào)處理異常,處理的是當前promise的返回的異常,而catch捕獲異常具有穿透作用,前面任何一個then函數(shù)出現(xiàn)異常都可以捕獲
問:兩者一起用時,前者會生效(因為err已經(jīng)將其處理,就不會再往下穿透)而走不到后面的catch
2Promise常用API及說明
2.1Promise構(gòu)造函數(shù):Promise(exector){}
(1)exector函數(shù),執(zhí)行器(resolve,reject)=>{}執(zhí)行器函數(shù)屬于同步執(zhí)行
(2)resolve函數(shù):PromiseState狀態(tài)變?yōu)閞esolved時調(diào)用的函數(shù)value=>{}
(3)reject函數(shù):PromiseState狀態(tài)變?yōu)閞ejected時調(diào)用的函數(shù)reason=>{}
說明:Promise支持同步也支持異步
2.2Promise.prototype.then方法 (onResolved,onRejected)=>{}
1)onResolved 函數(shù): 成功的回調(diào)函數(shù) (value) => {}
2)onRejected 函數(shù): 失敗的回調(diào)函數(shù) (reason) => {}
2.3Promise.prototype.catch 方法: (onRejected) => {}
onRejected 函數(shù): 失敗的回調(diào)函數(shù) (reason) => {}
說明: then()的語法糖, 相當于: then(undefined, onRejected),
異常穿透使用:當運行到最后,沒被處理的所有異常錯誤都會進入這個方法的回調(diào)函數(shù)中
說明:Promise.prototype.catch()方法是.then(undefined||null,rejection)的別名,用于指定發(fā)生錯誤時的回調(diào)函數(shù)
2.4Promise.prototype.finally 方法: ()=>{}
說明:方法的回調(diào)函數(shù)不需要參數(shù)。用于指定不管Promise對象最后狀態(tài)如何,都會執(zhí)行的操作
finally本質(zhì)上是then方法的特例:
promise
.finally(() => {
// 語句
});
// 等同于
promise
.then(
result => {
// 語句
return result;
},
error => {
// 語句
throw error;
}
);
代碼實現(xiàn):
Promise.prototype.finally = function (callback) {
let P = this.constructor; //Promise
return this.then(
value => P.resolve(callback()).then(() => value),
reason => P.resolve(callback()).then(() => { throw reason })
);
};
不管前面的Promise是resolved還是rejected,都會執(zhí)行回調(diào)函數(shù)callback并且總是返回原來的值
2.5Promise.resolve 方法 參數(shù)總類比較多,參照阮一峰老師的https://es6.ruanyifeng.com/#docs/promise#Promise-resolve
作用:直接將對象轉(zhuǎn)化為Promise對象
Promise.resolve('foo')
// 等價于
new Promise(resolve => resolve('foo'))
2.6Promise.reject方法
返回一個promise實例,該實例的狀態(tài)為rejected
const p = Promise.reject('出錯了');
// 等同于
const p = new Promise((resolve, reject) => reject('出錯了'))
p.then(null, function (s) {
console.log(s)
});
// 出錯了
Promise.reject方法的參數(shù)會原封不動地作為reject的理由,變成后續(xù)方法的參數(shù)
Promise.reject('出錯了')
.catch(e => {
console.log(e === '出錯了')
})
// true
2.7Promise.all()
方法用于將多個 Promise 實例,包裝成一個新的 Promise 實例。
const p = Promise.all([p1,p2,p3]),其中參數(shù)p1,p2,p3都是promise的實例,如果不是可以用Promise.resolve方法包裹
p的狀態(tài)p1,p2,p3決定,分為2種情況:
(1)只有p1、p2、p3的狀態(tài)都變成fulfilled,p的狀態(tài)才會變成fulfilled,此時p1、p2、p3的返回值組成一個數(shù)組,傳遞給p的回調(diào)函數(shù)。
(2)只要p1、p2、p3之中有一個被rejected,p的狀態(tài)就變成rejected,此時第一個被reject的實例的返回值,會傳遞給p的回調(diào)函數(shù)。
使用注意事項:作為參數(shù)的promise實例,自己定義了catch方法,那么它一旦被rejected,并不會觸發(fā)Promise.all()的catch方法,即如果參數(shù)中的實例定義了catch,即使rejected,也不會被promise.all的catch捕獲到,得到結(jié)果超出預(yù)期
const p1 = new Promise((resolve, reject) => {
resolve('hello');
})
.then(result => result)
.catch(e => e);
const p2 = new Promise((resolve, reject) => {
throw new Error('報錯了');
})
.then(result => result)
.catch(e => e);
Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));
// ["hello", Error: 報錯了]
上面代碼中,p1會resolved,p2首先會rejected,但是p2有自己的catch方法,該方法返回的是一個新的 Promise 實例,p2指向的實際上是這個實例。該實例執(zhí)行完catch方法后,也會變成resolved,導(dǎo)致Promise.all()方法參數(shù)里面的兩個實例都會resolved,因此會調(diào)用then方法指定的回調(diào)函數(shù),而不會調(diào)用catch方法指定的回調(diào)函數(shù)。
2.8Promise.race()
Promise.race() 方法參數(shù)同樣是多個promise實例,返回一個新的Promise實例
const p = Promise.race([p1,p2,p3])
說明:只要p1,p2,p3之中有一個實例率先改變狀態(tài)。p的狀態(tài)就跟著改變,那個率先改變的Promise實例的返回值,就傳遞給p的 回調(diào)函數(shù)
2.9.Promise.allSettled()
ES2020引入的用于確定一組異步操作是否都結(jié)束了(不管成功或失敗)
Promise.allSettled()方法接受一個數(shù)組作為參數(shù),數(shù)組的每個成員都是一個 Promise 對象,并返回一個新的 Promise 對象。只有等到參數(shù)數(shù)組的所有 Promise 對象都發(fā)生狀態(tài)變更(不管是fulfilled還是rejected),返回的 Promise 對象才會發(fā)生狀態(tài)變更。
注意:返回的新的promise實例的狀態(tài)總是resolved,它的回調(diào)函數(shù)會接收到一個數(shù)組作為參數(shù),該數(shù)組的每個成員對應(yīng)前面數(shù)組的每個promise對象
const resolved = Promise.resolve(42);
const rejected = Promise.reject(-1);
const allSettledPromise = Promise.allSettled([resolved, rejected]);
allSettledPromise.then(function (results) {
console.log(results);
});
// [
// { status: 'fulfilled', value: 42 }, //異步操作的結(jié)果
// { status: 'rejected', reason: -1 }
// ]
2.10Promise.any()
ES2021 引入了Promise.any()方法。該方法接受一組 Promise 實例作為參數(shù),包裝成一個新的 Promise 實例返回。
只要參數(shù)實例有一個變成fulfilled狀態(tài),包裝實例就會變成fulfilled狀態(tài);如果所有參數(shù)實例都變成rejected狀態(tài),包裝實例就會變成rejected狀態(tài)。
Promise.any()跟Promise.race()方法很像,只有一點不同,就是Promise.any()不會因為某個 Promise 變成rejected狀態(tài)而結(jié)束,必須等到所有參數(shù) Promise 變成rejected狀態(tài)才會結(jié)束。