Promise的聲明
首先翘鸭,promise
肯定是一個(gè)類(lèi)坤按,我們就用class
來(lái)聲明肴焊。
- 由于
new Promise((resolve, reject)=>{})
其屏,所以傳入一個(gè)參數(shù)(函數(shù))唧瘾,promisesA+規(guī)范里叫他executor
措译,傳入就執(zhí)行。 -
executor
里面有兩個(gè)參數(shù)饰序,一個(gè)叫resolve
(成功)领虹,一個(gè)叫reject
(失敗)求豫。 - 由于
resolve
和reject
可執(zhí)行塌衰,所以都是函數(shù),我們用let
聲明蝠嘉。
class Promise {
// 構(gòu)造器
constructor(executor) {
// 成功
let resolve = () => { };
// 失敗
let reject = () => { };
// 立即執(zhí)行
executor(resolve, reject);
}
}
解決基本狀態(tài)
promisesA+
規(guī)范對(duì)Promise
有規(guī)定:
-
Promise
存在三個(gè)狀態(tài)(state
):pending
最疆、fulfilled
、rejected
-
pending
(等待態(tài))為初始態(tài)蚤告,并可以轉(zhuǎn)化為fulfilled
(成功態(tài))和rejected
(失敗態(tài)) - 成功時(shí)努酸,不可轉(zhuǎn)為其他狀態(tài),且必須有一個(gè)不可改變的值(
value
) - 失敗時(shí)杜恰,不可轉(zhuǎn)為其他狀態(tài)获诈,且必須有一個(gè)不可改變的原因(
reason
) -
new Promise((resolve, reject)=>{resolve(value)})
,resolve
為成功箫章,接收參數(shù)value
烙荷,狀態(tài)改變?yōu)?code>fulfilled,不可再次改變 -
new Promise((resolve, reject)=>{reject(reason)})
檬寂,reject
為失敗终抽,接收參數(shù)reason
,狀態(tài)改變?yōu)?code>rejected桶至,不可再次改變 - 若是
executor
函數(shù)報(bào)錯(cuò)昼伴,直接執(zhí)行reject()
于是乎,我們獲得以下代碼:
class Promise {
constructor(executor) {
// 初始化state為等待態(tài)
this.state = 'pending';
// 成功的值
this.value = undefined;
// 失敗的原因
this.reason = undefined;
let resolve = value => {
// state改變,resolve調(diào)用就會(huì)失敗
if (this.state === 'pending') {
// resolve調(diào)用后镣屹,state轉(zhuǎn)化為成功態(tài)
this.state = 'fulfilled';
// 儲(chǔ)存成功的值
this.value = value;
}
};
let reject = reason => {
// state改變,reject調(diào)用就會(huì)失敗
if (this.state === 'pending') {
// reject調(diào)用后圃郊,state轉(zhuǎn)化為失敗態(tài)
this.state = 'rejected';
// 儲(chǔ)存失敗的原因
this.reason = reason;
}
};
// 如果executor執(zhí)行報(bào)錯(cuò),直接執(zhí)行reject
try{
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
}
then方法
promisesA+
規(guī)范規(guī)定:Promise
有一個(gè)叫做then
的方法女蜈,里面有兩個(gè)參數(shù):onFulfilled, onRejected
持舆,成功有成功的值色瘩,失敗有失敗的原因。
- 當(dāng)狀態(tài)
state
為fulfilled
逸寓,則執(zhí)行onFulfilled
居兆,傳入this.value
。當(dāng)狀態(tài)state
為rejected
竹伸,則執(zhí)行onRejected
泥栖,傳入this.reason
-
onFulfilled, onRejected
如果他們是函數(shù),則必須分別在fulfilled
勋篓,rejected
后被調(diào)用吧享,value
或reason
依次作為他們的第一個(gè)參數(shù)
class Promise {
constructor(executor) {...}
// then 方法 有兩個(gè)參數(shù)onFulfilled onRejected
then(onFulfilled, onRejected) {
// 狀態(tài)為fulfilled,執(zhí)行onFulfilled譬嚣,傳入成功的值
if (this.state === 'fulfilled') {
onFulfilled(this.value);
};
// 狀態(tài)為rejected钢颂,執(zhí)行onRejected,傳入失敗的原因
if (this.state === 'rejected') {
onRejected(this.reason);
};
}
}
解決異步實(shí)現(xiàn)
現(xiàn)在基本可以實(shí)現(xiàn)簡(jiǎn)單的同步代碼孤荣,但是當(dāng)resolve
在setTomeout
內(nèi)執(zhí)行甸陌,then
時(shí)state
還是pending
等待狀態(tài) 我們就需要在then
調(diào)用的時(shí)候,將成功和失敗存到各自的數(shù)組盐股,一旦reject
或者resolve
钱豁,就調(diào)用它們。
類(lèi)似于發(fā)布訂閱疯汁,先將then
里面的兩個(gè)函數(shù)儲(chǔ)存起來(lái)牲尺,由于一個(gè)promise
可以有多個(gè)then
,所以存在同一個(gè)數(shù)組內(nèi)幌蚊。
// 多個(gè)then的情況
let p = new Promise();
p.then();
p.then();
成功或者失敗時(shí)谤碳,forEach調(diào)用它們。
class Promise{
constructor(executor){
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
// 成功存放的數(shù)組
this.onResolvedCallbacks = [];
// 失敗存放法數(shù)組
this.onRejectedCallbacks = [];
let resolve = value => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
// 一旦resolve執(zhí)行溢豆,調(diào)用成功數(shù)組的函數(shù)
this.onResolvedCallbacks.forEach(fn=>fn());
}
};
let reject = reason => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
// 一旦reject執(zhí)行蜒简,調(diào)用失敗數(shù)組的函數(shù)
this.onRejectedCallbacks.forEach(fn=>fn());
}
};
try{
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled,onRejected) {
if (this.state === 'fulfilled') {
onFulfilled(this.value);
};
if (this.state === 'rejected') {
onRejected(this.reason);
};
// 當(dāng)狀態(tài)state為pending時(shí)
if (this.state === 'pending') {
// onFulfilled傳入到成功數(shù)組
this.onResolvedCallbacks.push(()=>{
onFulfilled(this.value);
})
// onRejected傳入到失敗數(shù)組
this.onRejectedCallbacks.push(()=>{
onRejected(this.reason);
})
}
}
}
解決鏈?zhǔn)秸{(diào)用
我門(mén)常常用到new Promise().then().then()
,這就是鏈?zhǔn)秸{(diào)用,用來(lái)解決回調(diào)地獄漩仙。
為了達(dá)成鏈?zhǔn)酱瓴纾覀兡J(rèn)在第一個(gè)then
里返回一個(gè)promise
。promisesA+
規(guī)范規(guī)定了一種方法队他,就是在then
里面返回一個(gè)新的promise
卷仑,稱(chēng)為promise2
:promise2 = new Promise((resolve, reject)=>{})
- 將這個(gè)
promise2
返回的值傳遞到下一個(gè)then
中 - 如果返回一個(gè)普通的值,則將普通的值傳遞給下一個(gè)
then
中
當(dāng)我們?cè)诘谝粋€(gè)then
中return
了一個(gè)參數(shù)(參數(shù)未知麸折,需判斷)锡凝。這個(gè)return
出來(lái)的新的promise
就是onFulfilled()
或onRejected()
的值。
promisesA+
規(guī)范則規(guī)定onFulfilled()
或onRejected()
的值垢啼,即第一個(gè)then
返回的值窜锯,叫做x
张肾,判斷x
的函數(shù)叫做resolvePromise
。
- 首先衬浑,要看
x
是不是promise
- 如果是
promise
捌浩,則取它的結(jié)果,作為新的promise2
成功的結(jié)果 - 如果是普通值工秩,直接作為
promise2
成功的結(jié)果 - 所以要比較
x
和promise2
-
resolvePromise
的參數(shù)有promise2
(默認(rèn)返回的promise
)、x
(我們自己return
的對(duì)象)进统、resolve
助币、reject
-
resolve
和reject
是promise2
的
class Promise {
constructor(executor) { ... }
then(onFulfilled, onRejected) {
// 聲明返回的promise2
let promise2 = new Promise((resolve, reject)=>{
if (this.state === 'fulfilled') {
let x = onFulfilled(this.value);
// resolvePromise函數(shù),處理自己return的promise和默認(rèn)的promise2的關(guān)系
resolvePromise(promise2, x, resolve, reject);
};
if (this.state === 'rejected') {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
};
if (this.state === 'pending') {
this.onResolvedCallbacks.push(()=>{
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
})
this.onRejectedCallbacks.push(()=>{
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
})
}
});
// 返回promise螟碎,完成鏈?zhǔn)? return promise2;
}
}
完成resolvePromise函數(shù)
promisesA+
規(guī)范規(guī)定了一段代碼眉菱,讓不同的promise
代碼互相套用,叫做resolvePromise
掉分。
如果x === promise2
俭缓,則是會(huì)造成循環(huán)引用,自己等待自己完成酥郭,則報(bào)“循環(huán)引用”錯(cuò)誤华坦。
let p = new Promise(resolve => {
resolve(0);
});
var p2 = p.then(data => {
// 循環(huán)引用,自己等待自己完成不从,一輩子完不成
return p2;
})
- 判斷
x
:
-
x
不能是null
-
x
是普通值 直接resolve(x)
-
x
是對(duì)象或者函數(shù)(包括promise
)惜姐,let then = x.then
- 當(dāng)
x
是對(duì)象或者函數(shù)(默認(rèn)promise
)
- 聲明了
then
- 如果取
then
報(bào)錯(cuò),則走reject()
- 如果
then
是個(gè)函數(shù)椿息,則用call
執(zhí)行then
歹袁,第一個(gè)參數(shù)是this
,后面是成功的回調(diào)和失敗的回調(diào) - 如果成功的回調(diào)還是
pormise
寝优,就遞歸繼續(xù)解析
- 成功和失敗只能調(diào)用一個(gè)条舔,所以設(shè)定一個(gè)
called
來(lái)防止多次調(diào)用
function resolvePromise(promise2, x, resolve, reject){
// 循環(huán)引用報(bào)錯(cuò)
if(x === promise2){
// reject報(bào)錯(cuò)
return reject(new TypeError('Chaining cycle detected for promise'));
}
// 防止多次調(diào)用
let called;
// x不是null 且x是對(duì)象或者函數(shù)
if (x != null && (typeof x === 'object' || typeof x === 'function')) {
try {
// A+規(guī)定,聲明then = x的then方法
let then = x.then;
// 如果then是函數(shù)乏矾,就默認(rèn)是promise了
if (typeof then === 'function') {
// 就讓then執(zhí)行 第一個(gè)參數(shù)是this 后面是成功的回調(diào) 和 失敗的回調(diào)
then.call(x, y => {
// 成功和失敗只能調(diào)用一個(gè)
if (called) return;
called = true;
// resolve的結(jié)果依舊是promise 那就繼續(xù)解析
resolvePromise(promise2, y, resolve, reject);
}, err => {
// 成功和失敗只能調(diào)用一個(gè)
if (called) return;
called = true;
reject(err);// 失敗了就失敗了
})
} else {
resolve(x); // 直接成功即可
}
} catch (e) {
// 也屬于失敗
if (called) return;
called = true;
// 取then出錯(cuò)了那就不要在繼續(xù)執(zhí)行了
reject(e);
}
} else {
resolve(x);
}
}
解決其他問(wèn)題
-
promisesA+
規(guī)范規(guī)定onFulfilled, onRejected
都是可選參數(shù)孟抗,如果他們不是函數(shù),必須被忽略
-
onFulfilled
返回一個(gè)普通的值妻熊,成功時(shí)直接等于value => value
-
onRejected
返回一個(gè)普通的值夸浅,失敗時(shí)如果直接等于value => value
,則會(huì)跑到下一個(gè)then
中的onFulfilled
中扔役,所以直接扔出一個(gè)錯(cuò)誤reason => throw err
-
promisesA+
規(guī)范規(guī)定onFulfilled
或onRejected
不能同步被調(diào)用帆喇,必須異步調(diào)用。我們就用setTimeout
解決異步問(wèn)題
- 如果
onFulfilled
或onRejected
報(bào)錯(cuò)亿胸,則直接返回reject()
class Promise{
constructor(executor){
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
let resolve = value => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.onResolvedCallbacks.forEach(fn=>fn());
}
};
let reject = reason => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(fn=>fn());
}
};
try{
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled,onRejected) {
// onFulfilled如果不是函數(shù)坯钦,就忽略onFulfilled预皇,直接返回value
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
// onRejected如果不是函數(shù),就忽略onRejected婉刀,直接扔出錯(cuò)誤
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
let promise2 = new Promise((resolve, reject) => {
if (this.state === 'fulfilled') {
// 異步
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
};
if (this.state === 'rejected') {
// 異步
setTimeout(() => {
// 如果報(bào)錯(cuò)
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
};
if (this.state === 'pending') {
this.onResolvedCallbacks.push(() => {
// 異步
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
// 異步
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0)
});
};
});
// 返回promise吟温,完成鏈?zhǔn)? return promise2;
}
}
catchresolve、reject突颊、race和all方法
class Promise {
constructor(executor) {
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
let resolve = value => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.onResolvedCallbacks.forEach(fn=>fn());
}
};
let reject = reason => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(fn=>fn());
}
};
try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled,onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
let promise2 = new Promise((resolve, reject) => {
if (this.state === 'fulfilled') {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
};
if (this.state === 'rejected') {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
};
if (this.state === 'pending') {
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0)
});
};
});
return promise2;
}
catch(fn){
return this.then(null,fn);
}
}
function resolvePromise(promise2, x, resolve, reject){
if(x === promise2){
return reject(new TypeError('Chaining cycle detected for promise'));
}
let called;
if (x != null && (typeof x === 'object' || typeof x === 'function')) {
try {
let then = x.then;
if (typeof then === 'function') {
then.call(x, y => {
if(called)return;
called = true;
resolvePromise(promise2, y, resolve, reject);
}, err => {
if(called)return;
called = true;
reject(err);
})
} else {
resolve(x);
}
} catch (e) {
if(called)return;
called = true;
reject(e);
}
} else {
resolve(x);
}
}
//resolve方法
Promise.resolve = function(val){
return new Promise((resolve,reject)=>{
resolve(val)
});
}
//reject方法
Promise.reject = function(val){
return new Promise((resolve,reject)=>{
reject(val)
});
}
//race方法
Promise.race = function(promises){
return new Promise((resolve,reject)=>{
for(let i=0;i<promises.length;i++){
promises[i].then(resolve,reject)
};
})
}
//all方法(獲取所有的promise鲁豪,都執(zhí)行then,把結(jié)果放到數(shù)組律秃,一起返回)
Promise.all = function(promises){
let arr = [];
let i = 0;
function processData(index,data){
arr[index] = data;
i++;
if(i == promises.length){
resolve(arr);
};
};
return new Promise((resolve,reject)=>{
for(let i=0;i<promises.length;i++){
promises[i].then(data=>{
processData(i,data);
},reject);
};
});
}