JS基于Promises/A+規范實現一個Promise
??本文基于Promises/A+實現一個Promise對象,幫助大家理解使用它。
??說明一下,Promises/A+是ES6中Promise的前身,規范可以參考:https://promisesaplus.com/
??ES6白皮書參考地址:https://tc39.es/ecma262/#sec-promise-objects
??MDN文檔:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise
??首先,根據Promises/A+規范,定義了一些術語,重要的就Promise和Thenable:??
Promise是一個具有then方法的對象或者函數,這個then方法需要滿足后面的一些規范。
Thenable是一個具有then方法的對象或者函數。
??從上面的術語可以看到,Promise是Thenable,但是Thenable不一定是Promise,主要區別有兩點:
??1. Promise對象具有三個狀態:pending, fulfilled, rejected??
1、當狀態是pending時,Promise的狀態可以變為fulfilled或者rejected。
2、當狀態是fulfilled時,Promise的狀態不可再改變,并具有一個不可改變的結果,結果可以是null、undefined、對象、函數、Promise或者Thenable等。
3、當狀態是rejected時,Promise的狀態不可再改變,并可具有一個不可改變的原因,原因可以是null、undefined、對象、函數、Promise或者Thenable等。
??2. Promise對象需要提供一個then方法,這個then方法需要接收兩個參數: ??
promise.then(onFulfilled, onRejected)
//onFulfilled是當promise狀態從pending變為fulfilled后需要執行的函數
//onRejected是當promise狀態從pending變為rejected后需要執行的函數
??而在ES6的規范中,Promise不僅滿足上面Promises/A+規范,還有其他一些特性來保證Promise的實用性,比如ES6中,Promise的構造函數需要傳入一個executor函數參數,它接收兩個函數作為參數:resolveFunc 和 rejectFunc,分別表示將Promise的狀態置為fulfilled還是rejected,因此,我們可以寫出Promise的構造函數大概是這個樣子的:
class MyPromise {
constructor(executor) {
//表示狀態是否已指定,保證狀態只會被改變一次
let specified = false
//狀態
let state = PENDING
//結果或者原因
let value = void 0
//fulfilled狀態的回調函數
let onFulfilledCallbacks = []
//rejected狀態的回調函數
let onRejectedCallbacks = []
//resolve函數,改變狀態為fulfilled
const resolve = (result) => { }
//reject函數,改變狀態為rejected
const reject = (reason) => { }
//then方法
this.then = (onFulfilled, onRejected) => { }
try {
executor(resolve, reject)
} catch (error) {
reject(error) //如果executor拋出異常,那么直接reject
}
}
}
??上面只是Promise大致的樣子,接下來我們就需要去實現這幾個函數即可:resolve、reject、then方法
??首先,我們需要先定義一些通用的函數與變量:??
//Promise的三個狀態
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
//判斷一個值是否是一個函數
const isFunction = value => value && typeof value === 'function' && value instanceof Function
//判斷一個值是否是一個Promise
const isPromise = value => value && (value instanceof MyPromise || value instanceof Promise)
//判斷一個值是否是一個對象
const isObject = value => value && typeof value === 'object' && value instanceof Object
//執行微任務,沒有返回結果
function runMicroTask(fn) {
//首先看微任務隊列函數是否存在,如果存在則使用微任務隊列執行
if (isFunction(queueMicrotask)) {
runMicroTask = f => queueMicrotask(f)
} else if (isObject(process) && isFunction(process.nextTick)) { //如果是Node.js環境
runMicroTask = f => process.nextTick(f)
} else if (isFunction(MutationObserver)) { //如果是瀏覽器環境
runMicroTask = f => {
const observer = new MutationObserver(f)
const node = document.createTextNode('')
observer.observe(node, { characterData: true })
node.data = '1' //觸發MutationObserver
}
} else { //如果都不存在,那么使用setTimeout(fn, 0)執行
runMicroTask = f => setTimeout(f, 0)
}
runMicroTask(fn)
}
??reject函數
??reject函數的視線很簡單,就是變更Promise的狀態和結果即可,結果往往是一個Error對象:??
//reject函數,改變狀態為rejected
const reject = (reason) => {
//當且僅當狀態是pending且未指定時進入
if (state === PENDING && !specified) {
[state, value, specified] = [REJECTED, reason, true]
//rejected狀態的回調函數,將其添加到onRejectedCallbacks數組中,判斷是否執行回調函數
runOrQueueTasks(onRejectedCallbacks, REJECTED)
}
}
??這里runOrQueueTasks其實就是將回調函數放到微任務里并準備執行回調函數,實現如下:??
const runOrQueueTasks = (callbacks, requireState, callback) => {
//如果callback是函數,那么將其添加到callbacks數組中
callback && callbacks.push(callback)
//如果是指定狀態,那么使用微任務執行
if (state === requireState) {
while (callbacks.length) {
const cb = callbacks.shift()
runMicroTask(() => cb(value)) // 使用微任務執行
}
}
}
??resolve函數
??resolve的函數實現邏輯更多一些,具體可以看看MDN的說明(跳轉),總結下來就是:??
1、resolve函數接收一個結果對象result
2、如果result結果對象是當前Promise自身,那么將會reject一個TypeError
3、如果result結果對象不是一個Thenable對象,那么Promise將會被立即FULFILLED,并采用這個result作為結果
4、如果result結果對象是一個Thenable對象,那么將會把Thenable對象的then方法放到微任務去執行,并Promise的resolve和reject作為then方法的兩個參數傳進入(近似可以這么認為),就是說Promise的結果又Thenable決定
??因此我們的resolve函數大概是這個樣子的:??
//resolve函數,改變狀態為fulfilled
const resolve = (result) => {
//當且僅當狀態是pending且未指定時進入
if (state === PENDING && !specified) {
//如果傳入的是當前Promise對象,那么直接reject
if (result === this) {
return reject(new TypeError('Chaining cycle detected for promise'))
}
specified = true;
//如果result是Thenable,那么調用(ES6白皮書)
//如果result是一個Promise,那么吸收它的狀態
try {
if (result && isFunction(result.then)) {
return runMicroTask(() => {
try {
const res = r => (specified = false, resolve(r)) //臨時打開
const rej = r => (specified = false, reject(r)) //臨時打開
result.then(res, rej)
} catch (error) {
reject(error)
}
})
}
} catch (error) {
return reject(error) //如果result.then拋出異常,那么直接reject
}
[state, value] = [FULFILLED, result]
//fulfilled狀態的回調函數,將其添加到onFulfilledCallbacks數組中,判斷是否執行回調函數
runOrQueueTasks(onFulfilledCallbacks, FULFILLED)
}
}
??then方法
??根據Promises/A+規范,then方法需要滿足下面的:??
1、調用方式:promise.then(onFulfilled, onRejected),這里onFulfilled、onRejected都必須是函數,否則將被忽略
2、onFulfilled、onRejected需要分別在promise變為fulfilled和rejected后執行,將結果或者原因作為第一個參數傳入,并且至多執行一次
3、onFulfilled、onRejected不能在當前上下文中執行,需要放到setTimeout、微任務這樣的上下文去執行
4、then方法如果調用多次,onFulfilled和onRejected需要按他們所在的then方法的調用順序依次執行
5、then方法方法需要返回一個新的Promise對象:promise2 = promise1.then(onFulfilled, onRejected)
1、如果onFulfilled和onRejected返回一個值x,那么將執行Promise Resolution Procedure,將promise2和x作為參數傳入
2、如果onFulfilled或者onRejected拋出異常,那么promise2將會使用這個異常進行reject
3、如果onFulfilled不是函數且promise1狀態是fulfilled,或者onRejected不是函數且promise1狀態是rejected,那么promise2將會吸收promise1的狀態,即promise1和promise2保持相同的結果和狀態
??因為then方法的實現大致如下
//then方法
this.then = (onFulfilled, onRejected) => {
const promise = new (this.constructor[Symbol.species] || MyPromise)((resolve, reject) => {
//如果onFulfilled是函數則調用
state !== REJECTED && runOrQueueTasks(onFulfilledCallbacks, FULFILLED, isFunction(onFulfilled) ? value => {
try {
const x = onFulfilled(value)
//根據函數返回結果進行Promise Resolution Procedure過程
promiseResolutionProcedure(promise, x, resolve, reject)
} catch (error) {
reject(error)
}
} : resolve)//否則根據當前狀態直接resolve
//如果onRejected是函數則調用
state !== FULFILLED && runOrQueueTasks(onRejectedCallbacks, REJECTED, isFunction(onRejected) ? value => {
try {
const x = onRejected(value)
//根據函數返回結果進行Promise Resolution Procedure過程
promiseResolutionProcedure(promise, x, resolve, reject)
} catch (error) {
reject(error)
}
} : reject)//否則根據當前狀態直接reject
})
return promise
}
??這里說下Promise Resolution Procedure過程
Promise Resolution Procedure過程采用這個表達方式:[[Resolve]](promise, x),其實可以理解為就是個函數處理過程,表示promise怎么去根據x的值變更狀態
1、如果promise和x是相同的對象,那么promise將會被reject(TypeError)
2、如果x是一個Promise,那么promise對象將會吸收x的狀態,即promise和x保持相同的結果和狀態
3、如果x是一個Thenable,那么調用Thenable的then方法,并將promise的resolve和reject函數作為參數傳入then方法調用
1、如果resolve函數被調用,并接收到結果y,那么接著執行Promise Resolution Procedure過程:[[Resolve]](promise, y)
2、如果reject函數被調用,那么接收到結果r,那么promise將會被reject(r)
3、resolve和reject函數只能被調用一次
4、如果then方法調用報錯,且resolve和reject函數都未被調用,那么promise將會被reject
4、否則promise將會被resolve(x)
??大致的實現代碼是這個樣子的:??
//Promise狀態處理過程
const promiseResolutionProcedure = (promise, x, resolve, reject) => {
// promise和x不能引用同一個對象
if (promise === x) {
throw new TypeError('Chaining cycle detected for promise')
}
//如果x是一個Promise,那么promise對象直接吸收x的狀態
if (isPromise(x)) { //這里兼容一下原生Promise
//這里ES6白皮書是放到微隊列中執行的(PromiseA+規范沒有確定)
return runMicroTask(() => x.then(resolve, reject))
}
//如果x是對象或者函數
if (isObject(x) || isFunction(x)) {
let ignoreCall = false
try {
//取then方法報錯,那么直接reject
let then = x.then
//如果then是一個函數,那么調用then方法
if (isFunction(then)) {
//調用采用x作為this,并傳入兩個參數resolve和reject,并要求resolve和reject只能調用一次
return runMicroTask(() => then.call(x, y => {
ignoreCall = ignoreCall || !promiseResolutionProcedure(promise, y, resolve, reject)
}, r => {
ignoreCall = ignoreCall || !reject(r)
}))
}
} catch (error) {
//如果then方法已經調用了resolve或reject,那么直接忽略
ignoreCall || reject(error)
}
}
//如果x不是一個對象或者函數,那么直接resolve
resolve(x)
}
??注:這里then方法的實現是參考Promises/A+規范,MDN上的描述大致含義和這個差不多,感興趣的可以去看看(跳轉)
??到這里我們的Promise就已經實現了,接下來說說Promise其它方法的拓展,這部分不是Promises/A+規范的內容,是ES6的Promise的拓展
??catch函數
??catch函數可以參考MDN上面的說明(跳轉),而我們的實現如下:??
class MyPromise {
//...其它代碼
//以下是ES6白皮書的拓展,不是Promise A+規范的內容
catch(onRejected) {
return this.then(null, onRejected)
}
}
??finally函數
??finally函數可以參考MDN上面的說明(跳轉),而我們的實現如下:
class MyPromise {
//...其它代碼
finally(onFinally) {
//onFinally是一個不接收任何參數的函數
//如果 onFinally 拋出錯誤或返回被拒絕的 promise,則新的 promise 將使用該值進行拒絕
const onThen = isFunction(onFinally)?() => {
const result = onFinally()
if (isPromise(result)) {
return result.then(() => this, () => result)
}
return this;
} : onFinally
return this.then(onThen, onThen)
}
}
??resolve函數
??resolve函數可以參考MDN上面的說明(跳轉),而我們的實現如下:??
class MyPromise {
//...其它代碼
static resolve(value) {
//如果value是一個Promise,那么直接返回
if (isPromise(value)) {
return value
}
//使用call(this)用以支持非Promise構造器(ES6白皮書)
const { promise, resolve } = MyPromise.withResolvers.call(this)
resolve(value) //直接resolve
return promise
}
}
??reject函數
??reject函數可以參考MDN上面的說明(跳轉),而我們的實現如下:?
class MyPromise {
//...其它代碼
static reject(reason) {
//使用call(this)用以支持非Promise構造器(ES6白皮書)
const { promise, reject } = MyPromise.withResolvers.call(this)
reject(reason) //直接reject
return promise
}
}
??all函數
??all函數可以參考MDN上面的說明(跳轉),而我們的實現如下:?
class MyPromise {
//...其它代碼
static all(promises) {
promises = [...promises]
const { promise, resolve, reject } = MyPromise.withResolvers()
const results = []
//如果是空數組,那么直接返回一個resolved的Promise
if (!promises.length) {
resolve(results)
} else {
promises.forEach((p, i) => {
MyPromise.resolve(p).then(value => {
results[i] = value
promises.pop() //每執行完成就彈出一個進行計數
//如果全部已經是fulfilled狀態,那么resolve結果
promises.length || resolve(results)
}, reject)
})
}
return promise
}
}
??race函數
??race函數可以參考MDN上面的說明(跳轉),而我們的實現如下:
class MyPromise {
//...其它代碼
static race(promises) {
promises = [...promises]
const { promise, resolve, reject } = MyPromise.withResolvers()
//只要有一個是fulfilled或者rejected,那么當前Promise就需要改變狀態
promises.forEach(p => MyPromise.resolve(p).then(resolve, reject))
return promise
}
}
??allSettled函數
??allSettled函數可以參考MDN上面的說明(跳轉),而我們的實現如下:
class MyPromise {
//...其它代碼
static allSettled(promises) {
promises = [...promises]
const { promise, resolve } = MyPromise.withResolvers()
const results = []
//如果是空數組,那么直接返回一個resolved的Promise
if (!promises.length) {
resolve(results)
} else {
promises.forEach((p, i) => {
MyPromise.resolve(p).then(value => {
results[i] = { status: FULFILLED, value }
promises.pop() //每執行完成就彈出一個進行計數
//全部Promise已經是fulfilled或者rejected狀態了,那么resolve
promises.length || resolve(results)
}, reason => {
results[i] = { status: REJECTED, reason }
promises.pop() //每執行完成就彈出一個進行計數
//全部Promise已經是fulfilled或者rejected狀態了,那么resolve
promises.length || resolve(results)
})
})
}
return promise
}
}
??any函數
??any函數可以參考MDN上面的說明(跳轉),而我們的實現如下:
class MyPromise {
//...其它代碼
static any(promises) {
promises = [...promises]
const { promise, resolve, reject } = MyPromise.withResolvers()
const errors = []
//如果是空數組,那么直接返回一個rejected的Promise
if (!promises.length) {
reject(new AggregateError(errors, 'All promises were rejected'))
} else {
promises.forEach((p, i) => {
MyPromise.resolve(p).then(resolve, reason => {
errors[i] = reason
promises.pop() //每執行完成就彈出一個進行計數
//如果有rejected,那么收集所有rejected并最后全局reject
promises.length || reject(new AggregateError(errors, 'All promises were rejected'))
})
})
}
return promise
}
}
??try函數
??try函數可以參考MDN上面的說明(跳轉),而我們的實現如下:??
class MyPromise {
//...其它代碼
static try(fn, ...args) {
//使用call(this)用以支持非Promise構造器(ES6白皮書)
const { promise, resolve, reject } = MyPromise.withResolvers.call(this)
try {
const result = fn(...args)
resolve(result)
} catch (error) {
reject(error)
}
return promise
}
}
??withResolvers函數
??withResolvers函數可以參考MDN上面的說明(跳轉),而我們的實現如下:
class MyPromise {
//...其它代碼
static withResolvers() {
let resolve, reject
const promise = new this((res, rej) => {
resolve = res
reject = rej
})
return { promise, resolve, reject }
}
}
??最后附上自己實現的Promise完整代碼:
查看代碼
//Promise的三個狀態
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
//判斷一個值是否是一個函數
const isFunction = value => value && typeof value === 'function' && value instanceof Function
//判斷一個值是否是一個Promise
const isPromise = value => value && (value instanceof MyPromise || value instanceof Promise)
//判斷一個值是否是一個對象
const isObject = value => value && typeof value === 'object' && value instanceof Object
//執行微任務,沒有返回結果
function runMicroTask(fn) {
//首先看微任務隊列函數是否存在,如果存在則使用微任務隊列執行
if (isFunction(queueMicrotask)) {
runMicroTask = f => queueMicrotask(f)
} else if (isObject(process) && isFunction(process.nextTick)) { //如果是Node.js環境
runMicroTask = f => process.nextTick(f)
} else if (isFunction(MutationObserver)) { //如果是瀏覽器環境
runMicroTask = f => {
const observer = new MutationObserver(f)
const node = document.createTextNode('')
observer.observe(node, { characterData: true })
node.data = '1' //觸發MutationObserver
}
} else { //如果都不存在,那么使用setTimeout(fn, 0)執行
runMicroTask = f => setTimeout(f, 0)
}
runMicroTask(fn)
}
class MyPromise {
constructor(executor) {
//表示狀態是否已指定,保證狀態只會被改變一次
let specified = false
//狀態
let state = PENDING
//結果或者原因
let value = void 0
//fulfilled狀態的回調函數
let onFulfilledCallbacks = []
//rejected狀態的回調函數
let onRejectedCallbacks = []
//如果想看promise運行的狀態和結果,可以使用下面的代碼
Object.defineProperty(this, 'state', { get() { return state }, configurable: false, enumerable: false })
Object.defineProperty(this, 'value', { get() { return value }, configurable: false, enumerable: false })
const runOrQueueTasks = (callbacks, requireState, callback) => {
//如果callback是函數,那么將其添加到callbacks數組中
callback && callbacks.push(callback)
//如果是指定狀態,那么使用微任務執行
if (state === requireState) {
while (callbacks.length) {
const cb = callbacks.shift()
runMicroTask(() => cb(value)) // 使用微任務執行
}
}
}
//resolve函數,改變狀態為fulfilled
const resolve = (result) => {
//當且僅當狀態是pending且未指定時進入
if (state === PENDING && !specified) {
//如果傳入的是當前Promise對象,那么直接reject
if (result === this) {
return reject(new TypeError('Chaining cycle detected for promise'))
}
specified = true;
//如果result是Thenable,那么調用(ES6白皮書)
//如果result是一個Promise,那么吸收它的狀態
try {
if (result && isFunction(result.then)) {
return runMicroTask(() => {
try {
const res = r => (specified = false, resolve(r)) //臨時打開
const rej = r => (specified = false, reject(r)) //臨時打開
result.then(res, rej)
} catch (error) {
reject(error)
}
})
}
} catch (error) {
return reject(error) //如果result.then拋出異常,那么直接reject
}
[state, value] = [FULFILLED, result]
//fulfilled狀態的回調函數,將其添加到onFulfilledCallbacks數組中,判斷是否執行回調函數
runOrQueueTasks(onFulfilledCallbacks, FULFILLED)
}
}
//reject函數,改變狀態為rejected
const reject = (reason) => {
//當且僅當狀態是pending且未指定時進入
if (state === PENDING && !specified) {
[state, value, specified] = [REJECTED, reason, true]
//rejected狀態的回調函數,將其添加到onRejectedCallbacks數組中,判斷是否執行回調函數
runOrQueueTasks(onRejectedCallbacks, REJECTED)
}
}
//Promise狀態處理過程
const promiseResolutionProcedure = (promise, x, resolve, reject) => {
// promise和x不能引用同一個對象
if (promise === x) {
throw new TypeError('Chaining cycle detected for promise')
}
//如果x是一個Promise,那么promise對象直接吸收x的狀態
if (isPromise(x)) { //這里兼容一下原生Promise
//這里ES6白皮書是放到微隊列中執行的(PromiseA+規范沒有確定)
return runMicroTask(() => x.then(resolve, reject))
}
//如果x是對象或者函數
if (isObject(x) || isFunction(x)) {
let ignoreCall = false
try {
//取then方法報錯,那么直接reject
let then = x.then
//如果then是一個函數,那么調用then方法
if (isFunction(then)) {
//調用采用x作為this,并傳入兩個參數resolve和reject,并要求resolve和reject只能調用一次
return runMicroTask(() => then.call(x, y => {
ignoreCall = ignoreCall || !promiseResolutionProcedure(promise, y, resolve, reject)
}, r => {
ignoreCall = ignoreCall || !reject(r)
}))
}
} catch (error) {
//如果then方法已經調用了resolve或reject,那么直接忽略
ignoreCall || reject(error)
}
}
//如果x不是一個對象或者函數,那么直接resolve
resolve(x)
}
//then方法
this.then = (onFulfilled, onRejected) => {
const promise = new (this.constructor[Symbol.species] || MyPromise)((resolve, reject) => {
//如果onFulfilled是函數則調用
state !== REJECTED && runOrQueueTasks(onFulfilledCallbacks, FULFILLED, isFunction(onFulfilled) ? value => {
try {
const x = onFulfilled(value)
//根據函數返回結果進行Promise Resolution Procedure過程
promiseResolutionProcedure(promise, x, resolve, reject)
} catch (error) {
reject(error)
}
} : resolve)//否則根據當前狀態直接resolve
//如果onRejected是函數則調用
state !== FULFILLED && runOrQueueTasks(onRejectedCallbacks, REJECTED, isFunction(onRejected) ? value => {
try {
const x = onRejected(value)
//根據函數返回結果進行Promise Resolution Procedure過程
promiseResolutionProcedure(promise, x, resolve, reject)
} catch (error) {
reject(error)
}
} : reject)//否則根據當前狀態直接reject
})
return promise
}
try {
executor(resolve, reject)
} catch (error) {
reject(error) //如果executor拋出異常,那么直接reject
}
}
//以下是ES6白皮書的拓展,不是Promise A+規范的內容
catch(onRejected) {
return this.then(null, onRejected)
}
finally(onFinally) {
//onFinally是一個不接收任何參數的函數
//如果 onFinally 拋出錯誤或返回被拒絕的 promise,則新的 promise 將使用該值進行拒絕
const onThen = isFunction(onFinally) ? () => {
const result = onFinally()
if (isPromise(result)) {
return result.then(() => this, () => result)
}
return this;
} : onFinally
return this.then(onThen, onThen)
}
static resolve(value) {
//如果value是一個Promise,那么直接返回
if (isPromise(value)) {
return value
}
//使用call(this)用以支持非Promise構造器(ES6白皮書)
const { promise, resolve } = MyPromise.withResolvers.call(this)
resolve(value) //直接resolve
return promise
}
static reject(reason) {
//使用call(this)用以支持非Promise構造器(ES6白皮書)
const { promise, reject } = MyPromise.withResolvers.call(this)
reject(reason) //直接reject
return promise
}
static all(promises) {
promises = [...promises]
const { promise, resolve, reject } = MyPromise.withResolvers()
const results = []
//如果是空數組,那么直接返回一個resolved的Promise
if (!promises.length) {
resolve(results)
} else {
promises.forEach((p, i) => {
MyPromise.resolve(p).then(value => {
results[i] = value
promises.pop() //每執行完成就彈出一個進行計數
//如果全部已經是fulfilled狀態,那么resolve結果
promises.length || resolve(results)
}, reject)
})
}
return promise
}
static race(promises) {
promises = [...promises]
const { promise, resolve, reject } = MyPromise.withResolvers()
//只要有一個是fulfilled或者rejected,那么當前Promise就需要改變狀態
promises.forEach(p => MyPromise.resolve(p).then(resolve, reject))
return promise
}
static allSettled(promises) {
promises = [...promises]
const { promise, resolve } = MyPromise.withResolvers()
const results = []
//如果是空數組,那么直接返回一個resolved的Promise
if (!promises.length) {
resolve(results)
} else {
promises.forEach((p, i) => {
MyPromise.resolve(p).then(value => {
results[i] = { status: FULFILLED, value }
promises.pop() //每執行完成就彈出一個進行計數
//全部Promise已經是fulfilled或者rejected狀態了,那么resolve
promises.length || resolve(results)
}, reason => {
results[i] = { status: REJECTED, reason }
promises.pop() //每執行完成就彈出一個進行計數
//全部Promise已經是fulfilled或者rejected狀態了,那么resolve
promises.length || resolve(results)
})
})
}
return promise
}
static any(promises) {
promises = [...promises]
const { promise, resolve, reject } = MyPromise.withResolvers()
const errors = []
//如果是空數組,那么直接返回一個rejected的Promise
if (!promises.length) {
reject(new AggregateError(errors, 'All promises were rejected'))
} else {
promises.forEach((p, i) => {
MyPromise.resolve(p).then(resolve, reason => {
errors[i] = reason
promises.pop() //每執行完成就彈出一個進行計數
//如果有rejected,那么收集所有rejected并最后全局reject
promises.length || reject(new AggregateError(errors, 'All promises were rejected'))
})
})
}
return promise
}
static try(fn, ...args) {
//使用call(this)用以支持非Promise構造器(ES6白皮書)
const { promise, resolve, reject } = MyPromise.withResolvers.call(this)
try {
const result = fn(...args)
resolve(result)
} catch (error) {
reject(error)
}
return promise
}
static withResolvers() {
let resolve, reject
const promise = new this((res, rej) => {
resolve = res
reject = rej
})
return { promise, resolve, reject }
}
static get [Symbol.species]() {
return MyPromise
}
[Symbol.toStringTag]() {
return "MyPromise"
}
}
??驗證
??我們主要在瀏覽器環境下驗證,我們可以嘗試幾個例子,把Promise換成我們自定義的MyPromise,結果是一樣的:
??例子一
Promise.resolve()
.then(() => {
console.log(0)
return Promise.resolve(4)
})
.then(res => {
console.log(res)
})
Promise.resolve()
.then(() => {
console.log(1);
})
.then(() => {
console.log(2);
})
.then(() => {
console.log(3);
})
.then(() => {
console.log(5);
})
.then(() => {
console.log(6);
})
??例子二
new Promise(function(resolve, reject) {
console.log(1);
resolve();
console.log(2);
}).then(function() {
console.log(4);
});
setTimeout(()=>console.log(5))
console.log(3);
??例子三
const first = () => (new Promise((resolve, reject) => {
console.log(1);
let p = new Promise((resolve, reject) => {
console.log(2);
setTimeout(() => {
console.log(6);
resolve(7);
}, 0)
resolve(4);
})
resolve(5);
p.then((arg) => {
console.log(arg);
});
}));
first().then((arg) => {
console.log(arg);
});
console.log(3);
??總結
??以上實現是個人總結,模擬Promise的實現過程,基于ES6的實現,如果有什么錯誤,歡迎指出!

浙公網安備 33010602011771號