什么是 Promise
參考 MDN 定義Promise
cosnt p = new Promise((resolve,reject)=>{})
一個 Promise 必然處于以下幾種狀態(tài)之一:
peding:初始狀態(tài),既沒有被兌現(xiàn),也沒有被拒絕。
fulfilled:意味著操作成功完成。
rejected:意味著操作失敗。
為什么使用Promise
假設有一下代碼,實現(xiàn)每過一秒鐘輸出一句話
function fn1(callback) {
setTimeout(()=>{
console.log('fn1')
callback()
}, 1000)
}
function fn2(callback) {
setTimeout(()=>{
console.log('fn2')
callback()
}, 1000)
}
function fn3() {
setTimeout(()=>{
console.log('fn3')
}, 1000)
}
fn1(function(){
fn2(function(){
fn3()
})
})
上面 fn1 里調(diào)用fn2,fn2 里調(diào)用 fn3 這種就形成了回調(diào)地獄,而使用 Promise可以讓代碼變得更優(yōu)雅。下面用 Promise 改造
function fn1(){
return new Promise((resolve,reject)=>{
setTeimeout(()=>{
resolve('fn1')
},1000)
})
}
function fn2(){
return new Promise((resolve,reject)=>{
setTeimeout(()=>{
resolve('fn2')
},1000)
})
}
function fn3(){
return new Promise((resolve,reject)=>{
setTeimeout(()=>{
resolve('fn3')
},1000)
})
}
fn1()
.then(fn2)
.then(fn3)
如何手寫一個 Promise
我們先考慮如何使用Promise
可以new 一個promise創(chuàng)建一個實例,接收一個函數(shù)作為參數(shù),這個函數(shù)有兩個參數(shù)分別是resolve,reject
const p = new Promise((resolve, reject) => {
//成功回調(diào)
resolve(data)
//失敗回調(diào)
reject(reason)
});
有 then 方法,支持鏈式調(diào)用
p.then(console.log('f1'),console.error('f2'))
.then(console.log('f3'),console.error('f4'))
下面開始手寫一個promise
constructor
我們知道new 一個promise實例時,參數(shù)fn數(shù)是是同步執(zhí)行的
class MyPromise {
constructor(fn) {
const resolve = (data) => {};
const reject = (reason) => {};
fn.call(undefined, resolve, reject);
}
then(onFulfilled, onRejected) {}
}
console.log(1)
const p = new MyPromise((resolve, reject) => {
console.log("執(zhí)行了");
});
console.log(2)

一個promise必須處于以下三種狀態(tài)之一:pending(待定)、fulfilled(實現(xiàn))或rejected(拒絕),處于pending狀態(tài)下的promise可以轉為fulfilled或者rejected狀態(tài),一但狀態(tài)改變之后,狀態(tài)就不可變了。這樣在我們的promise中添加上狀態(tài)部分的代碼
class MyPromise {
//2.1.1
#status = "pending";
constructor(fn) {
const resolve = (data) => {
//2.1.2.1
if (this.#status !== "pending") return;
this.#status = "fulfilled";
};
const reject = (reason) => {
//2.1.3.1
if (this.#status !== "pending") return;
this.#status = "rejected";
};
fn.call(undefined, resolve, reject);
}
then(onFulfilled, onRejected) {}
}
resolve和reject執(zhí)行可以傳遞參數(shù),

下面添參數(shù)部分的代碼
class MyPromise {
//規(guī)范 2.1.1
#status = "pending";
#result = undefined;
constructor(fn) {
const resolve = (data) => {
//規(guī)范 2.1.2.1
if (this.#status !== "pending") return;
this.#status = "fulfilled";
//2.1.2.2
this.#result = data;
};
const reject = (reason) => {
//規(guī)范 2.1.3.1
if (this.#status !== "pending") return;
this.#status = "rejected";
//2.1.3.2
this.#result = reason;
};
fn.call(undefined, resolve, reject);
}
then(onFulfilled, onRejected) {}
}
還有一種情況,new promise的時候拋出一個錯誤時,promise狀態(tài)變?yōu)閞ejected,結果為拋出的錯誤

所以調(diào)用fn是需要try catch處理
class MyPromise {
//規(guī)范 2.1.1
#status = "pending";
#result = undefined;
constructor(fn) {
const resolve = (data) => {
//規(guī)范 2.1.2.1
if (this.#status !== "pending") return;
this.#status = "fulfilled";
//2.1.2.2
this.#result = data;
};
const reject = (reason) => {
//規(guī)范 2.1.3.1
if (this.#status !== "pending") return;
this.#status = "rejected";
//2.1.3.2
this.#result = reason;
};
try {
fn.call(undefined, resolve, reject);
} catch (error) {
reject(error)
}
}
then(onFulfilled, onRejected) {}
}
then

then接收兩個參數(shù),onFulfilled 和 onRejected,promise狀態(tài)為fulfilled時執(zhí)行onFulfilled回調(diào),狀態(tài)為rejected時執(zhí)行onRejected回調(diào),then方法支持鏈式調(diào)用,所以then返回的還是一個promise
class MyPromise {
//規(guī)范 2.1.1
#status = "pending";
#result = undefined;
constructor(fn) {
const resolve = (data) => {
//規(guī)范 2.1.2.1
if (this.#status !== "pending") return;
this.#status = "fulfilled";
//2.1.2.2
this.#result = data;
};
const reject = (reason) => {
//規(guī)范 2.1.3.1
if (this.#status !== "pending") return;
this.#status = "rejected";
//2.1.3.2
this.#result = reason;
};
try {
fn.call(undefined, resolve, reject);
} catch (error) {
this.#result = error;
}
}
then(onFulfilled, onRejected) {
if(this.#status==='fulfilled'){
onFulfilled(this.#result)
}
if(this.#status==='rejected'){
onRejected(this.#result)
}
//2.2.7
return new MyPromise((resolve, reject) => {});
}
}
規(guī)范2.2.4 onFulfilled 和 onRejected 只有在執(zhí)行環(huán)境堆棧僅包含平臺代碼時才可被調(diào)用,所以在執(zhí)行onFulfilled和onRejected時要用異步調(diào)用
class MyPromise {
#status = "pending"; //規(guī)范2.1.1 初始狀態(tài)為 pending
#result = undefined; //返回結果
//接收一個 fn 函數(shù),
constructor(fn) {
const resolve = (data) => {
//規(guī)范2.1.2 不能轉換為其他任何狀態(tài)
if (this.#status !== "pending") return;
this.#status = "fulfilled"; //規(guī)范2.1.2 狀態(tài)變?yōu)?fulfilled
this.#result = data;
};
//規(guī)范 2.1.3.2 有一個失敗原因
const reject = (reason) => {
//規(guī)范2.1.3 不能轉換為其他任何狀態(tài)
if (this.#status !== "pending") return;
this.#status = "rejected"; //2.1.3 狀態(tài)變?yōu)?rejected
this.#result = reason;
};
// 如果函數(shù)執(zhí)行過程中出錯,狀態(tài)變?yōu)閞ejected
try {
fn.call(undefined, resolve, reject);
} catch (error) {
this.reject(error);
}
}
//2.2 有一個 then 方法,// 2.2.1 有兩個可選參數(shù)
then(onFulfilled, onRejected) {
//2.2.1.1 如果onFulfilled不是一個函數(shù),它必須被忽略
//2.2.5 onFulfilled和onRejected必須作為函數(shù)被調(diào)用(即沒有this值
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : () => {};
// 2.2.1.2 如果onRejected不是一個函數(shù),它必須被忽略
//2.2.5 onFulfilled和onRejected必須作為函數(shù)被調(diào)用(即沒有this值
onRejected = typeof onRejected === "function" ? onRejected : () => {};
//2.2.7 必須返回一個 promise
cosnt p2 = new MyPromise((resolve, reject) => {
if (this.#status === "fulfilled") {
//2.2.4 onFulfilled或onRejected不能在執(zhí)行上下文堆棧中只包含平臺代碼之前調(diào)用
setTimeout(() => {
onFulfilled(this.#result);
});
}
if (this.#status === "rejected") {
setTimeout(() => {
onRejected(this.#result);
});
}
});
}
return p2
}
//測試 輸出 1 promise1 4 2
console.log("1");
var p = new MyPromise((resolve, reject) => {
console.log("promise1");
resolve(2);
});
p.then(
(res) => {
console.log(res)
},
() => {
console.log("reject1");
}
);
console.log("4");
測試結果看似沒有問題,如果代碼稍微改動一下,就有問題了
console.log("1");
var p = new MyPromise((resolve, reject) => {
setTimeout(()=>{
console.log("promise1");
resolve(2);
})
});
p.then(
(res) => {
console.log(res)
},
() => {
console.log("reject1");
}
);
console.log("4");

resolve的結果不輸出了,因為then方法中只對
fulfilled和rejected的狀態(tài)做了處理,pending狀態(tài)時沒有處理,setTimeout中的代碼是放到異步任務隊列(宏任務)中處理的,運行到p.then時,promise狀態(tài)始終是pending狀態(tài)下面在then中加入pending狀態(tài)的處理
class MyPromise {
#status = "pending"; //規(guī)范2.1.1 初始狀態(tài)為 pending
#result = undefined; //返回結果
//接收一個 fn 函數(shù),
constructor(fn) {
this.queue = [];
this.state = "pending";
const resolve = (data) => {
//規(guī)范2.1.2 不能轉換為其他任何狀態(tài)
if (this.state !== "pending") return;
this.state = "fulfilled"; //規(guī)范2.1.2 狀態(tài)變?yōu)?fulfilled
this.#result = data;
};
//規(guī)范 2.1.3.2 有一個失敗原因
const reject = (reason) => {
//規(guī)范2.1.3 不能轉換為其他任何狀態(tài)
if (this.state !== "pending") return;
this.state = "rejected"; //2.1.3 狀態(tài)變?yōu)?rejected
this.#result = reason;
};
// 如果函數(shù)執(zhí)行過程中出錯,狀態(tài)變?yōu)閞ejected
try {
// this.queue.push([resolve, reject]);
fn.call(undefined, resolve, reject);
} catch (error) {
reject(error);
}
}
//2.2.1 有一個then方法,有兩個可選參數(shù)
then(onFulfilled, onRejected) {
//2.2.1.1 如果onFulfilled不是一個函數(shù),它必須被忽略
//2.2.5 onFulfilled和onRejected必須作為函數(shù)被調(diào)用(即沒有this值
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : () => {};
// 2.2.1.2 如果onRejected不是一個函數(shù),它必須被忽略
//2.2.5 onFulfilled和onRejected必須作為函數(shù)被調(diào)用(即沒有this值
onRejected = typeof onRejected === "function" ? onRejected : () => {};
//2.2.7 必須返回一個 promise
const p2 = new MyPromise((resolve, reject) => {
//2.2.2.2 在promise實現(xiàn)之前不得調(diào)用它。
if (this.state === "fulfilled") {
//2.2.4 onFulfilled或onRejected不能在執(zhí)行上下文堆棧中只包含平臺代碼之前調(diào)用。
setTimeout((data) => {
onFulfilled(this.#result);
});
}
//2.2.3.2 在promise被拒絕之前不得調(diào)用它。
if (this.state === "rejected") {
//2.2.2.1 它必須在promise實現(xiàn)后調(diào)用,并以promise的值作為其第一個參數(shù)。
setTimeout((reason) => {
onRejected(reason);
});
}
//
if (this.state === "pending") {
}
});
return p2;
}
#resolvePromise(promise, x) {
try {
if (promise === x) {
}
} catch (error) {}
}
}
問題來了,pending狀態(tài)時要做什么呢?
我們知道hen方法中的onFulfilled和onRejected執(zhí)行時機一定是等promise狀態(tài)變?yōu)閒ulfilled或者rejected后才執(zhí)行。也就是說要等到resolve或reject執(zhí)行之后再執(zhí)行。很簡單,resolve時調(diào)用onFulfilled就行了,reject時調(diào)用onRejected,
注意then方法支持多次調(diào)用,如何多次調(diào)用呢,很簡單,將onFulfilled和onRejected放入一個隊列中,resolve執(zhí)行時調(diào)用所有成功的回調(diào)onFulfilled,reject執(zhí)行時調(diào)用所有失敗的回調(diào)onRejected
class MyPromise {
#status = "pending"; //規(guī)范2.1.1 初始狀態(tài)為 pending
#result = undefined; //返回結果
//接收一個 fn 函數(shù),
constructor(fn) {
this.queue = []; //添加一個隊列,存儲onFulfilled, onRejected
this.state = "pending";
const resolve = (data) => {
console.log('data:',data)
//規(guī)范2.1.2 不能轉換為其他任何狀態(tài)
if (this.state !== "pending") return;
this.state = "fulfilled"; //規(guī)范2.1.2 狀態(tài)變?yōu)?fulfilled
this.#result = data;
// 執(zhí)行resolve時再調(diào)用所有onFulfilled
this.queue.map(callbacks=>{
const task = this.queue.shift()
task[0](data)
})
};
//規(guī)范 2.1.3.2 有一個失敗原因
const reject = (reason) => {
//規(guī)范2.1.3 不能轉換為其他任何狀態(tài)
if (this.state !== "pending") return;
this.state = "rejected"; //2.1.3 狀態(tài)變?yōu)?rejected
this.#result = reason;
// 執(zhí)行reject時再調(diào)用所有onRejected
this.queue.map(callbacks=>{
const task = this.queue.shift()
task[1](reason)
})
};
// 如果函數(shù)執(zhí)行過程中出錯,狀態(tài)變?yōu)閞ejected
try {
// this.queue.push([resolve, reject]);
fn.call(undefined, resolve, reject);
} catch (error) {
reject(error);
}
}
//2.2.1 有一個then方法,有兩個可選參數(shù)
then(onFulfilled, onRejected) {
//2.2.1.1 如果onFulfilled不是一個函數(shù),它必須被忽略
//2.2.5 onFulfilled和onRejected必須作為函數(shù)被調(diào)用(即沒有this值
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : () => {};
// 2.2.1.2 如果onRejected不是一個函數(shù),它必須被忽略
//2.2.5 onFulfilled和onRejected必須作為函數(shù)被調(diào)用(即沒有this值
onRejected = typeof onRejected === "function" ? onRejected : () => {};
//2.2.7 必須返回一個 promise
const p2 = new MyPromise((resolve, reject) => {
//2.2.2.2 在promise實現(xiàn)之前不得調(diào)用它。
if (this.state === "fulfilled") {
//2.2.4 onFulfilled或onRejected不能在執(zhí)行上下文堆棧中只包含平臺代碼之前調(diào)用。
setTimeout((data) => {
onFulfilled(this.#result);
});
}
//2.2.3.2 在promise被拒絕之前不得調(diào)用它。
if (this.state === "rejected") {
//2.2.2.1 它必須在promise實現(xiàn)后調(diào)用,并以promise的值作為其第一個參數(shù)。
setTimeout((reason) => {
onRejected(reason);
});
}
//pending狀態(tài)時,將onFulfilled, onRejected存入隊列
if (this.state === "pending") {
this.queue.push([onFulfilled, onRejected]);
}
});
return p2;
}
}
下面測試一下,then方法中的回調(diào)成功執(zhí)行了,但是和正常的promise執(zhí)行順序不太一樣
console.log("1");
var p = new MyPromise((resolve, reject) => {
setTimeout(() => {
console.log("2");
resolve(4);
console.log("3");
});
});
p.then(
(res) => {
console.log('res',res);
},
() => {
console.log("reject1");
}
);
console.log("5");

測試正常promise輸出的執(zhí)行結果
console.log("1");
var p = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("2");
resolve(4);
console.log("3");
});
});
p.then(
(res) => {
console.log('res',res);
},
() => {
console.log("reject1");
}
);
console.log("5");
可以看到resolve的執(zhí)行是在最后執(zhí)行的。如何讓resolve在后面執(zhí)行呢,很簡單放到setTimeout中就行啦

class MyPromise {
#status = "pending"; //規(guī)范2.1.1 初始狀態(tài)為 pending
#result = undefined; //返回結果
//接收一個 fn 函數(shù),
constructor(fn) {
this.queue = []; //添加一個隊列,存儲onFulfilled, onRejected
const resolve = (data) => {
//規(guī)范2.1.2 不能轉換為其他任何狀態(tài)
if (this.#status !== "pending") return;
setTimeout(() => {
this.#status = "fulfilled"; //規(guī)范2.1.2 狀態(tài)變?yōu)?fulfilled
this.#result = data;
//2.2.6.1 如果/當promise被實現(xiàn)時,所有相應的onFulfilled回調(diào)函數(shù)必須按照它們發(fā)起then調(diào)用的順序執(zhí)行。
this.queue.map((callbacks) => {
const task = callbacks[0];
task(data);
});
});
};
//規(guī)范 2.1.3.2 有一個失敗原因
const reject = (reason) => {
//規(guī)范2.1.3 不能轉換為其他任何狀態(tài)
if (this.#status !== "pending") return;
setTimeout(() => {
this.#status = "rejected"; //2.1.3 狀態(tài)變?yōu)?rejected
this.#result = reason;
//2.2.6.2 如果/當promise被拒絕時,所有相應的onRejected回調(diào)函數(shù)必須按照它們發(fā)起then調(diào)用的順序執(zhí)行。
this.queue.map((callbacks) => {
const task = callbacks[1];
task(reason);
});
});
};
// 如果函數(shù)執(zhí)行過程中出錯,狀態(tài)變?yōu)閞ejected
try {
// this.queue.push([resolve, reject]);
fn(resolve, reject);
} catch (error) {
reject(error);
}
}
//2.2.1 有一個then方法,有兩個可選參數(shù)
then(onFulfilled, onRejected) {
//2.2.1.1 如果onFulfilled不是一個函數(shù),它必須被忽略
//2.2.5 onFulfilled和onRejected必須作為函數(shù)被調(diào)用(即沒有this值
const onFulfilledcallback =
typeof onFulfilled === "function" ? onFulfilled : () => {};
// 2.2.1.2 如果onRejected不是一個函數(shù),它必須被忽略
//2.2.5 onFulfilled和onRejected必須作為函數(shù)被調(diào)用(即沒有this值
const onRejectedcallback =
typeof onRejected === "function" ? onRejected : () => {};
//2.2.7 必須返回一個 promise
const p2 = new MyPromise((resolve, reject) => {
//2.2.2.2 在promise實現(xiàn)之前不得調(diào)用onFulfilled。
if (this.#status === "fulfilled") {
//2.2.4 onFulfilled或onRejected不能在執(zhí)行上下文堆棧中只包含平臺代碼之前調(diào)用。
setTimeout(() => {
try {
onFulfilledcallback(this.#result);
} catch (e) {
reject(e);
}
});
}
//2.2.3.2 在promise被拒絕之前不得調(diào)用它。
if (this.#status === "rejected") {
//2.2.2.1 它必須在promise實現(xiàn)后調(diào)用,并以promise的值作為其第一個參數(shù)。
setTimeout(() => {
try {
onRejectedcallback(this.#result);
} catch (e) {
reject(e);
}
});
}
//2.2.6then方法可以在同一個promise上多次調(diào)用。
if (this.#status === "pending") {
this.queue.push([onFulfilled, onRejected]);
}
});
return p2;
}
#resolutionProcedure(promise, x, resolve, reject) {
try {
if (promise === x) {
}
} catch (error) {}
}
}
在測試一下
console.log("1");
var p = new MyPromise((resolve, reject) => {
setTimeout(() => {
console.log("2");
resolve(4);
console.log("3");
});
});
p.then(
(res) => {
console.log("resolve", res);
},
(reason) => {
console.log("reject", reason);
}
);
console.log("5");
結果和正常的promise一樣了

我們知道then方法中onFulfilled或onRejected可以不是一個函數(shù)
var p = new Promise((resolve,reject)=>{
resolve(1)
})
p.then(undefined,reason=>{
console.log(reason)
}).then((res)=>{
console.log(res)
},undefined)
需要再then方法中處理一下resolve和reject的返回值
class MyPromise {
...
//2.2.1 有一個then方法,有兩個可選參數(shù)
then(onFulfilled, onRejected) {
//2.2.1.1 如果onFulfilled不是一個函數(shù),它必須被忽略
//2.2.5 onFulfilled和onRejected必須作為函數(shù)被調(diào)用(即沒有this值
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : (data) => data;
// 2.2.1.2 如果onRejected不是一個函數(shù),它必須被忽略
//2.2.5 onFulfilled和onRejected必須作為函數(shù)被調(diào)用(即沒有this值
onRejected =
typeof onRejected === "function"
? onRejected
: (reason) => {
throw reason;
};
//2.2.7 必須返回一個 promise
const p2 = new MyPromise((resolve, reject) => {
//2.2.2.2 在promise實現(xiàn)之前不得調(diào)用onFulfilled。
if (this.#status === "fulfilled") {
//2.2.4 onFulfilled或onRejected不能在執(zhí)行上下文堆棧中只包含平臺代碼之前調(diào)用。
setTimeout(() => {
try {
const x = onFulfilled(this.#result);
this.#resolvePromise(p2, x, resolve, reject);
} catch (e) {
//2.2.7.2 如果onFulfilled或onRejected拋出異常e,則promise2必須以e作為原因被拒絕
reject(e);
}
});
}
//2.2.3.2 在promise被拒絕之前不得調(diào)用它。
if (this.#status === "rejected") {
//2.2.2.1 它必須在promise實現(xiàn)后調(diào)用,并以promise的值作為其第一個參數(shù)。
setTimeout(() => {
try {
const x = onRejected(this.#result);
this.#resolvePromise(p2, x, resolve, reject);
} catch (e) {
//2.2.7.2 如果onFulfilled或onRejected拋出異常e,則promise2必須以e作為原因被拒絕
reject(e);
}
});
}
//2.2.6then方法可以在同一個promise上多次調(diào)用。
if (this.#status === "pending") {
this.queue.push([
() => {
setTimeout(() => {
try {
let x = onFulfilled(this.#result);
this.#resolvePromise(p2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
},
() => {
setTimeout(() => {
try {
let x = onRejected(this.#result);
this.#resolvePromise(p2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
},
]);
}
});
return p2;
}
/**
* 對resolve()、reject() 進行改造增強 針對resolve()和reject()中不同值情況 進行處理
* @param {promise} promise2 promise1.then方法返回的新的promise對象
* @param {[type]} x promise1中onFulfilled或onRejected的返回值
* @param {[type]} resolve promise2的resolve方法
* @param {[type]} reject promise2的reject方法
*/
#resolvePromise(promise2, x, resolve, reject) {
//2.3.1 如果promise和x引用同一個對象,則以TypeError為原因拒絕promise
if (x === promise2) {
return reject(new TypeError("Chaining cycle detected for promise"));
}
//2.3.2 如果x是一個promise,采用其狀態(tài)
if (x instanceof MyPromise) {
if (x.#status === "pending") {
x.then(
(y) => {
this.#resolvePromise(promise2, y, resolve, reject);
},
() => {
reject(x.#result);
}
);
}
if (x.#status === "fulfilled") {
resolve(x.#result);
}
if (x.#status === "rejected") {
reject(x.#result);
}
}
//2.3.3 否則,如果x是一個對象或函數(shù):
//注意x不能為null
else if (x !== null && (x instanceof Object || typeof x === "function")) {
try {
//2.3.3.2
var then = x.then;
} catch (e) {
//2.3.3.3
reject(e);
}
if (typeof then === "function") {
//定義called表示y,r是否被調(diào)用過
let called = false;
//2.3.3.3.4
try {
then.call(
x,
//2.3.3.3.1
(y) => {
//2.3.3.3.3
if (called) return;
this.#resolvePromise(p2, y, resolve, reject);
called = true;
},
//2.3.3.3.2
(r) => {
//2.3.3.3.3
if (called) return;
reject(r);
called = true;
}
);
} catch (e) {
//2.3.3.3.4.1
if (called) return;
//2.3.3.3.4.2
reject(e);
}
} else {
resolve(x);
}
}
//2.3.4 如果x不是對象或函數(shù),則用x來實現(xiàn)promise。
else {
resolve(x);
}
try {
} catch (error) {}
}
}
實現(xiàn)鏈式調(diào)用
上面代碼中then方法返回一個promsie,那么onFulFilled和onReject的結果如何處理呢?
參考promise a+規(guī)范2.2.7
- 2.2.7.1如果onFulfilled或onRejected返回一個值
x,則運行Promise Resolution Procedure [[Resolve]](promise2, x)。 - 2.2.7.2 如果onFulfilled或onRejected拋出異常e,則promise2必須以e作為原因被拒絕。
- 2.2.7.3 如果onFulfilled不是一個函數(shù)且promise1被實現(xiàn),則promise2必須以與promise1相同的值被實現(xiàn)。
- 2.2.7.4 如果onRejected不是一個函數(shù)且promise1被拒絕,則promise2必須以與promise1相同的原因被拒絕。
這里我們定義個函數(shù)resolvePromise(promise,x resolve,reject) 來處理x,在then方法中分別在不同狀態(tài)下用resolvePromise方法處理
class MyPromise {
...
//2.2.1 有一個then方法,有兩個可選參數(shù)
then(onFulfilled, onRejected) {
//2.2.1.1 如果onFulfilled不是一個函數(shù),它必須被忽略
//2.2.5 onFulfilled和onRejected必須作為函數(shù)被調(diào)用(即沒有this值
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : () => {};
// 2.2.1.2 如果onRejected不是一個函數(shù),它必須被忽略
//2.2.5 onFulfilled和onRejected必須作為函數(shù)被調(diào)用(即沒有this值
onRejected = typeof onRejected === "function" ? onRejected : () => {};
//2.2.7 必須返回一個 promise
const p2 = new MyPromise((resolve, reject) => {
//2.2.2.2 在promise實現(xiàn)之前不得調(diào)用onFulfilled。
if (this.#status === "fulfilled") {
//2.2.4 onFulfilled或onRejected不能在執(zhí)行上下文堆棧中只包含平臺代碼之前調(diào)用。
setTimeout(() => {
try {
const x = onFulfilled(this.#result);
this.#resolvePromise(p2, x, resolve, reject);
} catch (e) {
//2.2.7.2 如果onFulfilled或onRejected拋出異常e,則promise2必須以e作為原因被拒絕
reject(e);
}
});
}
//2.2.3.2 在promise被拒絕之前不得調(diào)用它。
if (this.#status === "rejected") {
//2.2.2.1 它必須在promise實現(xiàn)后調(diào)用,并以promise的值作為其第一個參數(shù)。
setTimeout(() => {
try {
const x = onRejected(this.#result);
this.#resolvePromise(p2, x, resolve, reject);
} catch (e) {
//2.2.7.2 如果onFulfilled或onRejected拋出異常e,則promise2必須以e作為原因被拒絕
reject(e);
}
});
}
//2.2.6then方法可以在同一個promise上多次調(diào)用。
if (this.#status === "pending") {
this.queue.push([
() => {
setTimeout(() => {
try {
let x = onFulfilled(this.#result);
this.#resolvePromise(p2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
},
() => {
setTimeout(() => {
try {
let x = onRejected(this.#result);
this.#resolvePromise(p2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
},
]);
}
});
return p2;
}
/**
* 對resolve()、reject() 進行改造增強 針對resolve()和reject()中不同值情況 進行處理
* @param {promise} promise2 promise1.then方法返回的新的promise對象
* @param {[type]} x promise1中onFulfilled或onRejected的返回值
* @param {[type]} resolve promise2的resolve方法
* @param {[type]} reject promise2的reject方法
*/
#resolvePromise(promise2, x, resolve, reject) {
}
}
按照下面規(guī)范實現(xiàn)resolvePromise

/**
* 對resolve()、reject() 進行改造增強 針對resolve()和reject()中不同值情況 進行處理
* @param {promise} promise2 promise1.then方法返回的新的promise對象
* @param {[type]} x promise1中onFulfilled或onRejected的返回值
* @param {[type]} resolve promise2的resolve方法
* @param {[type]} reject promise2的reject方法
*/
#resolvePromise(promise2, x, resolve, reject) {
//2.3.1 如果promise和x引用同一個對象,則以TypeError為原因拒絕promise
if (x === promise2) {
return reject(new TypeError("Chaining cycle detected for promise"));
}
//2.3.2 如果x是一個promise,采用其狀態(tài)
if (x instanceof MyPromise) {
if (x.#status === "pending") {
x.then(
(y) => {
this.#resolvePromise(promise2, y, resolve, reject);
},
() => {
reject(x.#result);
}
);
}
if (x.#status === "fulfilled") {
resolve(x.#result);
}
if (x.#status === "rejected") {
reject(x.#result);
}
}
//2.3.3 否則,如果x是一個對象或函數(shù):
//注意x不能為null
else if (x !== null && (typeof x === "object" || typeof x === "function")) {
var then;
try {
//2.3.3.2
then = x.then;
if (typeof then === "function") {
//定義called表示y,r是否被調(diào)用過
let called = false;
//2.3.3.3.4
try {
then.call(
x,
//2.3.3.3.1
(y) => {
//2.3.3.3.3
if (called) return;
called = true;
this.#resolvePromise(promise2, y, resolve, reject);
},
//2.3.3.3.2
(r) => {
//2.3.3.3.3
if (called) return;
called = true;
reject(r);
}
);
} catch (e) {
//2.3.3.3.4.1
if (called) return;
//2.3.3.3.4.2
reject(e);
}
} else {
resolve(x);
}
} catch (e) {
//2.3.3.3
reject(e);
}
}
//2.3.4 如果x不是對象或函數(shù),則用x來實現(xiàn)promise。
else {
resolve(x);
}
}
下面測試一下
console.log("1");
var p = new MyPromise((resolve, reject) => {
setTimeout(() => {
console.log("2");
resolve(4);
console.log("3");
});
});
p.then(
(res) => {
console.log("resolve1", res);
return new MyPromise((resolve, reject) => {
resolve(123);
});
},
(reason) => {
console.log("reject1", reason);
}
).then(
(res) => {
console.log("resolve2", res);
},
(reason) => {
console.log("reject2", reason);
}
);
console.log("5");
可以看到結果和替換成官方Promise的結果一致

