一、規(guī)范簡介
-
術(shù)語:
- Promise 是具有
then方法的對象或函數(shù),行為符合Promise/A+規(guī)范。 - thenable 是定義then方法得對象或函數(shù)
- value 是任何合法的Javascript值(包括undefined,ableable或promise)
- 異常 exception throw 語句拋出的值
- reason 是表明拒絕promise的原因
- Promise 是具有
-
要求
-
promise 的狀態(tài)
- pending:等待狀態(tài),可以轉(zhuǎn)換成其他狀態(tài)。
- fulfilled:成功狀態(tài),不能轉(zhuǎn)化為其他狀態(tài)。轉(zhuǎn)為該狀態(tài)需要一個value,該value不能改變。
- rejected:失敗狀態(tài),不能轉(zhuǎn)為其他狀態(tài)。轉(zhuǎn)為改狀態(tài)需要一個reason,該reason不能改變。
fulfilled與rejected是穩(wěn)定狀態(tài)
-
then 方法
- const promise2 = promise1.then(onFulfilled, onRejected)
- then方法的參數(shù)
- 兩個函數(shù)參數(shù)
- onFulfilled在promise完成后被調(diào)用,onRejected在Promise被拒絕執(zhí)行后調(diào)用
- 只能被調(diào)用一次
- then方法的調(diào)用:可以調(diào)用多次
- then方法的返回值:promise
- onFulfilled不是函數(shù),promise1的狀態(tài)是fulfilled :這時 promise2的狀態(tài)是fulfilled,值同promise1
- onRejected不是函數(shù),promise1的狀態(tài)是rejected:這時promise2的狀態(tài)是 rejected,拒絕原因reason同promise1
- onFulfilled 或者onRejected return x 返回一個返回值,進(jìn)入Promise解析過程
-
Promise解析過程
- 抽象模型 resolve(promise, x)
- 如果promise和x指向相同的對象
- 如果x是一個promise:查看x的狀態(tài) pending 則需等待狀態(tài)改變,fulfilled value 為 promise的值 ,reject reason為promise的reason
- 如果x是一個對象或一個函數(shù): 執(zhí)行x的then方法
- 如果x不是對象也不是函數(shù):把x作為promise的值,設(shè)置成fulfilled狀態(tài)
-
二、根據(jù)規(guī)范打造自己的Promise
-
new Promise
定義一個 class 來證明 promise
new Promise((resolve, reject) => {}),傳入一個參數(shù)(函數(shù)),該函數(shù)為立即執(zhí)行函數(shù),這里面我們起名為 executor。executor 函數(shù)接收兩個參數(shù),resolve 與 reject,成功時resolve(value),失敗時reject(reason)。
-
promise 原型方法:
- .then()
- .catch()
- .finally()
-
promise 靜態(tài)方法
- Promise.resolve(value)
- Promise.reject(reason)
- Promise.all([p1, .....,pn])
- Promise.allSettled([p1, .....,pn])
- Promise.race([p1, .....,pn])
根據(jù)以上信息,我們大致架構(gòu)如下
class Promise { // 構(gòu)造器 constructor(executor) { // resolve() let resolve = value => {} // reject() let reject = reason => {} // 立即執(zhí)行 executor 方法 executor(resolve, reject); } // then 方法 then() {} // catch 方法 catch() {} // finall 方法 finally() {} } Promise.resolve = () => {} Promise.reject = () => {} Promise.all = () => {} Promise.allSettled = () => {} Promise.race = () => {}
-
promise 狀態(tài)
規(guī)范要求:Promise 狀態(tài)
- Promise 存在三個狀態(tài)(state):pending,fulfilled,rejected
- pending 為初始狀態(tài),可轉(zhuǎn)化為 fulfilled 和 rejected
- 成功后,不可轉(zhuǎn)為其他狀態(tài),且需要一個不可變值(value)
- 失敗后,不可轉(zhuǎn)為其他狀態(tài),且需要一個不可變原因(reason)
new Promise((resolve, reject) => {})- 成功時 resolve(value),接受參數(shù)value,狀態(tài)改為 fulfilled,此為穩(wěn)定狀態(tài),不可再次改變。
- 失敗時 reject(reason),接受參數(shù) reason,狀態(tài)改為 rejected,此為穩(wěn)定狀態(tài),不可再次改變。
- 執(zhí)行 executor 時報錯,則直接執(zhí)行 reject(reason)
根據(jù)以上信息,我們得到以下代碼:
class Promise {
// 構(gòu)造器
constructor(executor) {
// 狀態(tài) 默認(rèn)為 pending 狀態(tài)
this.state = "pending";
// 成功的值
this.value = undefined;
// 失敗的原因
this.reason = undefined;
// resolve(value) 將狀態(tài)改為 fulfilled 狀態(tài)
let resolve = value => {
this.value = value;
this.state = "fulfilled";
}
// reject(reason) 將狀態(tài)改為 rejected 狀態(tài)
let reject = reason => {
this.reason = reason;
this.state = "rejected";
}
// 如果 executor 報錯 立即執(zhí)行 reject
try{
// 立即執(zhí)行 executor 方法
executor(resolve, reject);
} catch(error) {
reject(error);
}
}
// then 方法
then() {}
// catch 方法
catch() {}
// finall 方法
finally() {}
}
Promise.resolve = () => {}
Promise.reject = () => {}
Promise.all = () => {}
Promise.allSettled = () => {}
Promise.race = () => {}
-
.then()方法規(guī)范要求:
.then()由于
.then()要求很多,我們進(jìn)行拆解,分為:- 基本要求
- 鏈?zhǔn)秸{(diào)用。
1. 基本要求:
一個 Promise 必須提供 then 方法,訪問其當(dāng)前或最終value或reason
-
then 接受兩個參數(shù)
promise.then(onFulfilled, onRejected)- then的兩個參數(shù)為可選參數(shù)。
- 如果參數(shù)不是函數(shù),則必須將其忽略。
- 如果 onFulfilled 是函數(shù)
- 必須在promise 成功后調(diào)用,以promise的值(value)作為第一個參數(shù),不能調(diào)用多次。
- 如果 onRejected 是函數(shù)
- 必須在promise 失敗后調(diào)用,以promise的原因(reason)作為第一個參數(shù),不能調(diào)用多次。
- onFulfilled 及 onRejected 必須作為函數(shù)調(diào)用(沒有this值)
異步調(diào)用:onFulfilled 或 onRejected 在執(zhí)行上下文堆棧(緊包含平臺代碼)之前不能調(diào)用
class Promise { // 構(gòu)造器 constructor(executor) {...} // then 方法 then(onFulfilled, onRejected) { // onFulfilled 為可選參數(shù) 如果不為函數(shù) 則忽略onFulfilled 直接返回 value onFulfilled = isFunction(onFulfilled) ? onFulfilled : value => value; // onRejected 為可選參數(shù) 如果不為函數(shù) 則忽略onFulfilled 直接拋出錯誤 onRejected = isFunction(onRejected) ? onRejected : error => { throw error}; // 如果 Promise 為 成功狀態(tài) 調(diào)用 onFulfilled 方法 傳入成功的 value if(this.state === "fulfilled") { // 異步調(diào)用 setTimeout(() => { onFulfilled(this.value); }, 0); } // 如果 Promise 為 失敗狀態(tài) 調(diào)用 onRejected 方法 傳入失敗的 reason if (this.state === "rejected") { // 異步調(diào)用 setTimeout(() => { onRejected(this.reason); }, 0); } } // catch 方法 catch() {} // finall 方法 finally() {} } Promise.resolve = () => {} Promise.reject = () => {} Promise.all = () => {} Promise.allSettled = () => {} Promise.race = () => {} // 輔助方法 // 判斷 obj 是不是 Function function isFunction(obj) { return !!obj && typeof obj === "function"; } // 判斷 obj 是不是 Object function isObject(obj) { return !!obj && typeof obj === "object"; } // 判斷 obj 是不是 Promise function isPromise(obj) { return !!obj && (typeof obj === "object" || typeof obj === "function") && typeof obj.then === "function"; }特殊情況:
new Promise((resolve, reject) => { setTimeout(() => { resolve(1); // reject("錯誤"); }, 200) })當(dāng) resolve 或者reject 在 setTimeout內(nèi)執(zhí)行時,由于setTimeout為異步方法,會先把它放到宏任務(wù)隊列當(dāng)中等待當(dāng)前任務(wù)執(zhí)行完成之后在執(zhí)行。當(dāng)前任務(wù)執(zhí)行到.then 時 Promise的狀態(tài)(state)還是pending(等待狀態(tài)),這時就會出現(xiàn)問題。
解決方案:
規(guī)范要求中有一條要求:
-
then 可能在同一 Promise中多次被調(diào)用
let p = new Promise(); p.then(); p.then();- 當(dāng)promise 成功,則所有相應(yīng)的 onFulfilled回調(diào)必須按照其原始調(diào)用的執(zhí)行順序執(zhí)行then
- 當(dāng)promise失敗,則所有相應(yīng)的onRejected回調(diào)必須按照其原始調(diào)用的執(zhí)行順序進(jìn)行then
根據(jù)這一要求,我們可以在then中增加 state為pending的處理,將onFulfilled 與onRejected方法存到各自的數(shù)組里面,一旦setTimeout中的resolve或者reject執(zhí)行了 ,就調(diào)用它們。
這樣除了能解決setTimeout異步問題,也能解決統(tǒng)一Promise多次調(diào)用then問題。
根據(jù)以上信息,得到以下代碼:
class Promise { constructor(executor) { this.state = "pending"; this.value = undefined; this.reason = undefined; // 成功存放方法的數(shù)組 this.onResolvedCallbacks = []; // 失敗存放方法的數(shù)組 this.onRejectedCallbacks = []; let resolve = value => { this.value = value; this.state = "fulfilled"; // 一旦 resolve 執(zhí)行, 則按順序 調(diào)用 成功數(shù)組 中的函數(shù) this.onResolvedCallbacks.forEach(fn => { fn(); }); } let reject = reason => { this.reason = reason; this.state = "rejected"; // 一旦 reject 執(zhí)行, 則按順序 調(diào)用 失敗數(shù)組 中的函數(shù) this.onRejectedCallbacks.forEach(fn => { fn(); }); } try{ executor(resolve, reject); } catch(error) { reject(error); } } // then 方法 then(onFulfilled, onRejected) { onFulfilled = isFunction(onFulfilled) ? onFulfilled : value => value; onRejected = isFunction(onRejected) ? onRejected : error => { throw error}; if(this.state === "fulfilled") { setTimeout(() => { onFulfilled(this.value); }, 0); } if (this.state === "rejected") { setTimeout(() => { onRejected(this.reason); }, 0); } // 如果 Promise 為 等待狀態(tài) // 由于不知道 是成功還是失敗,則需要兩個數(shù)組, // 將成功或失敗各自對應(yīng)的方法 push 到各自的數(shù)組當(dāng)中 if (this.state === "pending") { // onFulfilled 傳入到成功數(shù)組 this.onResolvedCallbacks.push(() => { // 異步調(diào)用 setTimeout(() => { onFulfilled(this.value); }, 0); }); // onRejected 傳入到成功的數(shù)組 this.onRejectedCallbacks.push(() => { // 異步調(diào)用 setTimeout(() => { onRejected(this.reason); }, 0); }) } } catch() {} finally() {} } Promise.resolve = () => {} Promise.reject = () => {} Promise.all = () => {} Promise.allSettled = () => {} Promise.race = () => {} function isFunction(obj) { return !!obj && typeof obj === "function"; } function isObject(obj) { return !!obj && typeof obj === "object"; } function isPromise(obj) { return !!obj && (typeof obj === "object" || typeof obj === "function") && typeof obj.then === "function"; }2. 鏈?zhǔn)秸{(diào)用
日常使用 Promise 時,常用到 new promise().then().then(),這就是鏈?zhǔn)秸{(diào)用。通過鏈?zhǔn)秸{(diào)用,我們就可以解決回調(diào)地獄問題。
規(guī)范中規(guī)定:
-
then 必須返回一個promise
promise2 = promise1.then(onFulfilled, onRejected);- 如果 onFulfilled 或 onRejected 執(zhí)行時報錯,則直接返回失敗
- onFulfilled 不是函數(shù),promise1的狀態(tài)是fulfilled :這時 promise2的狀態(tài)是fulfilled,值同promise1
- onRejected 不是函數(shù),promise1 的狀態(tài)是 rejected:這時promise2的狀態(tài)是 rejected,拒絕原因 reason 同promise1
- 如果一個 onFulfilled 或 onRejected 返回一個值 x(自己return x),則需要對x進(jìn)行處理,處理的函數(shù)叫做:resolvePromise(promise2, x)
-
規(guī)范中的resolvePromise(promise2, x) 規(guī)定
- 如果promise和x指向相同的對象,會導(dǎo)致循環(huán)調(diào)用,直接返回失敗
- 如果x是一個promise:查看x的狀態(tài) pending 則需等待狀態(tài)改變,fulfilled value 為 promise的值 ,reject reason為promise的reason
- 如果x是一個對象或一個函數(shù): 執(zhí)行x的then方法
- 如果 沒有x.then 則直接返回失敗
- 如果 有x.then 且為函數(shù),則執(zhí)行 then.call(),參數(shù):x 作為this,成功時的回調(diào),失敗時的回調(diào)。
- 如果成功的回調(diào)還是promise,值為y,再次調(diào)用 resolvePromise(promise2, y, resolve, reject)
- 如果失敗,則執(zhí)行失敗回到,原因為r,直接返回失敗
- 成功和失敗只能調(diào)用一個,所以設(shè)定一個isCalled來防止多次調(diào)用
- 如果 有x.then但不是函數(shù),則將x作為promise的值
- 如果x不是對象也不是函數(shù):把x作為promise的值,設(shè)置成fulfilled狀態(tài)
class Promise { // 構(gòu)造器 constructor(executor) {...} // then 方法 then(onFulfilled, onRejected) { // onFulfilled 為可選參數(shù) 如果不為函數(shù) 則忽略onFulfilled 直接返回 value onFulfilled = isFunction(onFulfilled) ? onFulfilled : value => value; // onRejected 為可選參數(shù) 如果不為函數(shù) 則忽略onFulfilled 直接拋出錯誤 onRejected = isFunction(onRejected) ? onRejected : error => { throw error}; // 如果 Promise 為 成功狀態(tài) 調(diào)用 onFulfilled 方法 傳入成功的 value if(this.state === "fulfilled") { // 異步調(diào)用 setTimeout(() => { try { let x = onFulfilled(this.value); resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }, 0); } // 如果 Promise 為 失敗狀態(tài) 調(diào)用 onRejected 方法 傳入失敗的 reason if (this.state === "rejected") { // 異步調(diào)用 setTimeout(() => { try { let x = onRejected(this.reason); resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }, 0); } // 如果 Promise 為 等待狀態(tài) // 由于不知道 是成功還是失敗,則需要兩個數(shù)組, // 將成功或失敗各自對應(yīng)的方法 push 到各自的數(shù)組當(dāng)中 if (this.state === "pending") { // onFulfilled 傳入到成功數(shù)組 this.onResolvedCallbacks.push(() => { // 異步調(diào)用 setTimeout(() => { try { let x = onFulfilled(this.value); resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }, 0); }); // onRejected 傳入到成功的數(shù)組 this.onRejectedCallbacks.push(() => { // 異步調(diào)用 setTimeout(() => { try { let x = onRejected(this.reason); resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }, 0); }); } } // catch 方法 catch() {} // finall 方法 finally() {} } Promise.resolve = () => {} Promise.reject = () => {} Promise.all = () => {} Promise.allSettled = () => {} Promise.race = () => {} function resolvePromise(promise2, x, resolve, reject) { // 如果 x 和 promise2 指向相同 if (x === promise2) { reject(new TypeError("Chaining cycle detected for promise")); } // 如果x為promise 則采用其狀態(tài) if (isPromise(x)) { if (x.state === "pending") { return x.then(()=> { resolve(x.value); }, () => { reject(x.reason); }) } if (x.state === "fulfilled") { return resolve(x.value); } if (x.state === "rejected") { return reject(x.reason); } } else if (isObject(x) || isFunction(x)) { // 如果x是對象或者函數(shù) let then; // 取 x.then try { then = x.then; } catch (error) { // 取x.then 如果報錯則直接失敗 reject(error); } // 如果 then 是 函數(shù) if (isFunction(then)) { // 只可以調(diào)用一個 let isCalled = false; try { then.call(x, y => { if (isCalled) { return; } isCalled = true; resolvePromise(promise2, y, resolve, reject); }, r => { if (isCalled) { return; } isCalled = true; reject(r); }) } catch (error) { // 執(zhí)行then報錯則直接返回失敗 if (isCalled) { return; } isCalled = true; reject(error); } } else { // 如果不是方法 則把x作為promsie的值 resolve(x); } } else { // x 既不是方法也不是函數(shù) 則把x作為promsie的值 resolve(x); } } // 輔助方法 // 判斷 obj 是不是 Function function isFunction(obj) { return !!obj && typeof obj === "function"; } // 判斷 obj 是不是 Object function isObject(obj) { return !!obj && typeof obj === "object"; } // 判斷 obj 是不是 Promise function isPromise(obj) { return !!obj && (typeof obj === "object" || typeof obj === "function") && typeof obj.then === "function"; }
-
catch 實現(xiàn)
報錯就走這個方法
// catch 方法 catch(fn) { return this.then(null, fn); }
-
finall 實現(xiàn)
不管成功還是失敗,最后都要執(zhí)行該方法,與 then不同
參數(shù):onFinally :Promise結(jié)束后調(diào)用的function
返回值: 返回了一個設(shè)置了finally回調(diào)函數(shù)的Promise對象
描述:如果你想在 promise 執(zhí)行完畢后無論其結(jié)果怎樣都做一些處理或清理時,
finally()方法可能是有用的。finally()雖然與.then(onFinally, onFinally)類似,它們不同的是:- 調(diào)用內(nèi)聯(lián)函數(shù)時,不需要多次聲明該函數(shù)或為該函數(shù)創(chuàng)建一個變量保存它。
- 由于無法知道
promise的最終狀態(tài),所以finally的回調(diào)函數(shù)中不接收任何參數(shù),它僅用于無論最終結(jié)果如何都要執(zhí)行的情況。 - 與
Promise.resolve(2).then(() => {}, () => {})(resolved的結(jié)果為undefined)不同,Promise.resolve(2).finally(() => {})resolved的結(jié)果為2。 - 同樣,
Promise.reject(3).then(() => {}, () => {})(resolved 的結(jié)果為undefined),Promise.reject(3).finally(() => {})rejected 的結(jié)果為3。
注意: 在
finally回調(diào)中throw(或返回被拒絕的promise)將以throw()指定的原因拒絕新的promise.// finall 方法 finally(fn) { return new Promise((resolve, reject) => { try { fn(); } catch (error) { reject(error); } if (this.state === "fulfilled") { resolve(this.value); } if (this.state === "rejected") { reject(this.reason); } }) }
-
Promise.resolve 實現(xiàn)
Promise.resolve = (value) => { return new Promise((resolve, reject) => { resolve(value); }); }
-
Promise.reject 實現(xiàn)
Promise.reject = (reason) => { return new Promise((resolve, reject) => { resolve(reason); }); }
-
Promise.all 實現(xiàn)
all 方法
Promise.all([p1, p2, p3])用于將多個promise實例,包裝成一個新的Promise實例,返回的實例就是普通的promise
它接收一個數(shù)組作為參數(shù)
數(shù)組里可以是Promise對象,也可以是別的值,只有Promise會等待狀態(tài)改變
當(dāng)所有的子Promise都完成,該Promise完成,返回值是全部值得數(shù)組
有任何一個失敗,該Promise失敗,返回值是第一個失敗的子Promise結(jié)果
Promise.all = (promiseArr) => { let result = []; let i = 0; function handleData(index, value, resolve) { result[index] = value; i++; if (i == promiseArr.length) { resolve(result); } } return new Promise((resolve, reject) => { for (let i = 0; i < promiseArr.length; i++) { if (isPromise(promiseArr[i])) { promiseArr[i].then(value => { handleData(i, value, resolve); }, reject) } else { handleData(i, promiseArr[i], resolve); } } }) }
-
Promise.allSettled 實現(xiàn)
allSettled 方法
Promise.allSettled([p1, p2, p3])用于將多個promise實例,包裝成一個新的Promise實例,返回的實例就是普通的promise
它接收一個數(shù)組作為參數(shù)
數(shù)組里是Promise對象
當(dāng)所有的子Promise都完成,該Promise完成,返回值是一個對象 包含每個子promise執(zhí)行后得狀態(tài)及對應(yīng)得值或原因
只要所有得子promise都執(zhí)行完成,結(jié)果Promise為fulfilled狀態(tài)
Promise.allSettled = (promiseArr) => { let result = []; let i = 0; function handleData(index, data, resolve) { result[index] = data; i++; if (i == promiseArr.length) { resolve(result); } } return new promise((resolve, reject) => { for (let i = 0; i < promiseArr.length; i++) { promiseArr[i].then(value => { handleData(i, {state: "fulfilled", value: value}, resolve); }, error => { handleData(i, {state: "rejected", reason: error}, resolve); }); } }); }
-
Promise.race 實現(xiàn)
race 方法 有一個完成就算完成,返回的promise狀態(tài)同第一個完成的
Promise.race = (promiseArr) => { return new promise((resolve, reject) => { for (let i = 0; i < promiseArr.length; i++) { promiseArr[i].then(resolve, reject); } }); }
-
完整代碼
class Promise { // 構(gòu)造器 constructor(executor) { // 狀態(tài) 默認(rèn)為 pending 狀態(tài) this.state = "pending"; // 成功的值 this.value = undefined; // 失敗的原因 this.reason = undefined; // 成功存放方法的數(shù)組 this.onResolvedCallbacks = []; // 失敗存放方法的數(shù)組 this.onRejectedCallbacks = []; // resolve(value) 將狀態(tài)改為 fulfilled 狀態(tài) let resolve = value => { this.value = value; this.state = "fulfilled"; // 一旦 resolve 執(zhí)行, 則按順序 調(diào)用 成功數(shù)組 中的函數(shù) this.onResolvedCallbacks.forEach(fn => { fn(); }); } // reject(reason) 將狀態(tài)改為 rejected 狀態(tài) let reject = reason => { this.reason = reason; this.state = "rejected"; // 一旦 reject 執(zhí)行, 則按順序 調(diào)用 失敗數(shù)組 中的函數(shù) this.onRejectedCallbacks.forEach(fn => { fn(); }); } // 如果 executor 報錯 立即執(zhí)行 reject try{ // 立即執(zhí)行 executor 方法 executor(resolve, reject); } catch(error) { reject(error); } } // then 方法 then(onFulfilled, onRejected) { // onFulfilled 為可選參數(shù) 如果不為函數(shù) 則忽略onFulfilled 直接返回 value onFulfilled = isFunction(onFulfilled) ? onFulfilled : value => value; // onRejected 為可選參數(shù) 如果不為函數(shù) 則忽略onFulfilled 直接拋出錯誤 onRejected = isFunction(onRejected) ? onRejected : error => { throw error}; // 如果 Promise 為 成功狀態(tài) 調(diào)用 onFulfilled 方法 傳入成功的 value if(this.state === "fulfilled") { // 異步調(diào)用 setTimeout(() => { try { let x = onFulfilled(this.value); resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }, 0); } // 如果 Promise 為 失敗狀態(tài) 調(diào)用 onRejected 方法 傳入失敗的 reason if (this.state === "rejected") { // 異步調(diào)用 setTimeout(() => { try { let x = onRejected(this.reason); resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }, 0); } // 如果 Promise 為 等待狀態(tài) // 由于不知道 是成功還是失敗,則需要兩個數(shù)組, // 將成功或失敗各自對應(yīng)的方法 push 到各自的數(shù)組當(dāng)中 if (this.state === "pending") { // onFulfilled 傳入到成功數(shù)組 this.onResolvedCallbacks.push(() => { // 異步調(diào)用 setTimeout(() => { try { let x = onFulfilled(this.value); resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }, 0); }); // onRejected 傳入到成功的數(shù)組 this.onRejectedCallbacks.push(() => { // 異步調(diào)用 setTimeout(() => { try { let x = onRejected(this.reason); resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }, 0); }); } } // catch 方法 catch(fn) { return this.then(null, fn); } // finall 方法 finally(fn) { return new Promise((resolve, reject) => { try { fn(); } catch (error) { reject(error); } if (this.state === "fulfilled") { resolve(this.value); } if (this.state === "rejected") { reject(this.reason); } }) } } Promise.resolve = (value) => { return new Promise((resolve, reject) => { resolve(value); }); } Promise.reject = (reason) => { return new Promise((resolve, reject) => { resolve(reason); }); } Promise.all = (promiseArr) => { let result = []; let i = 0; function handleData(index, value, resolve) { result[index] = value; i++; if (i == promiseArr.length) { resolve(result); } } return new Promise((resolve, reject) => { for (let i = 0; i < promiseArr.length; i++) { if (isPromise(promiseArr[i])) { promiseArr[i].then(value => { handleData(i, value, resolve); }, reject) } else { handleData(i, promiseArr[i], resolve); } } }) } Promise.allSettled = (promiseArr) => { let result = []; let i = 0; function handleData(index, data, resolve) { result[index] = data; i++; if (i == promiseArr.length) { resolve(result); } } return new promise((resolve, reject) => { for (let i = 0; i < promiseArr.length; i++) { promiseArr[i].then(value => { handleData(i, {state: "fulfilled", value: value}, resolve); }, error => { handleData(i, {state: "rejected", reason: error}, resolve); }); } }); } Promise.race = (promiseArr) => { return new promise((resolve, reject) => { for (let i = 0; i < promiseArr.length; i++) { promiseArr[i].then(resolve, reject); } }); } function resolvePromise(promise2, x, resolve, reject) { // 如果 x 和 promise2 指向相同 if (x === promise2) { reject(new TypeError("Chaining cycle detected for promise")); } // 如果x為promise 則采用其狀態(tài) if (isPromise(x)) { if (x.state === "pending") { return x.then(()=> { resolve(x.value); }, () => { reject(x.reason); }) } if (x.state === "fulfilled") { return resolve(x.value); } if (x.state === "rejected") { return reject(x.reason); } } else if (isObject(x) || isFunction(x)) { // 如果x是對象或者函數(shù) let then; // 取 x.then try { then = x.then; } catch (error) { // 取x.then 如果報錯則直接失敗 reject(error); } // 如果 then 是 函數(shù) if (isFunction(then)) { // 只可以調(diào)用一個 let isCalled = false; try { then.call(x, y => { if (isCalled) { return; } isCalled = true; resolvePromise(promise2, y, resolve, reject); }, r => { if (isCalled) { return; } isCalled = true; reject(r); }) } catch (error) { // 執(zhí)行then報錯則直接返回失敗 if (isCalled) { return; } isCalled = true; reject(error); } } else { // 如果不是方法 則把x作為promsie的值 resolve(x); } } else { // x 既不是方法也不是函數(shù) 則把x作為promsie的值 resolve(x); } } // 輔助方法 // 判斷 obj 是不是 Function function isFunction(obj) { return !!obj && typeof obj === "function"; } // 判斷 obj 是不是 Object function isObject(obj) { return !!obj && typeof obj === "object"; } // 判斷 obj 是不是 Promise function isPromise(obj) { return !!obj && (typeof obj === "object" || typeof obj === "function") && typeof obj.then === "function"; }
-
驗證promise是否正確
先在后面加上下述代碼
npm 有一個promises-aplus-tests插件 npm i promises-aplus-tests -g 可以全局安裝 mac用戶最前面加上sudo
命令行 promises-aplus-tests [js文件名] 即可驗證
// 目前是通過他測試 他會測試一個對象 // 語法糖 Promise.defer = Promise.deferred = function () { let dfd = {} dfd.promise = new Promise((resolve,reject)=>{ dfd.resolve = resolve; dfd.reject = reject; }); return dfd; } module.exports = Promise; //npm install promises-aplus-tests 用來測試自己的promise 符不符合promisesA+規(guī)范