#### 手寫Promise源碼
// promise有三種狀態(tài) pending 等待 fulfilled 成功 rejected 失敗
// 且狀態(tài)改變只能從pending -> fulfilled(從等待到成功) 或者 pending -> rejected(從等待到失敗) 且狀態(tài)改變后不可更改
// 聲明三種狀態(tài)常量
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
// 創(chuàng)建Promise類
class MyProise {
? ? // Promise 對(duì)象需要傳入一個(gè)執(zhí)行器函數(shù) 該執(zhí)行器函數(shù)會(huì)立即執(zhí)行 并且該執(zhí)行器函數(shù)有兩個(gè)參數(shù)成功回調(diào) 失敗回調(diào)
? ? // 并且兩個(gè)參數(shù)resolve和reject是來(lái)更改函數(shù)狀態(tài)的
? ? // resolve -> fulfilled(從等待到成功)
? ? // reject -> rejected(從等待到失敗)
? ? constructor(executor) {
? ? ? ? // 使用trycatch是為了捕獲執(zhí)行器函數(shù)中的運(yùn)行異常 如出現(xiàn)異常則執(zhí)行catch邏輯 將Promise類的函數(shù)狀態(tài)更改為rejected并將失敗原因返回
? ? ? ? try {
? ? ? ? ? ? // 執(zhí)行執(zhí)行器函數(shù) 參數(shù)為更新函數(shù)狀態(tài)的兩個(gè)函數(shù)
? ? ? ? ? ? executor(this.resolve, this.reject)
? ? ? ? } catch (error) {
? ? ? ? ? ? // 捕獲執(zhí)行器函數(shù)異常 將Promise類的函數(shù)狀態(tài)更改為rejected
? ? ? ? ? ? this.reject(error)
? ? ? ? }
? ? }
? ? //記錄函數(shù)狀態(tài)并初始化函數(shù)狀態(tài)為pending
? ? status = PENDING
? ? // 記錄函數(shù)成功后的返回值 作為成功返回值給then方法成功回調(diào)
? ? value = undefined
? ? // 記錄函數(shù)失敗后的返回值 作為失敗原因給then方法失敗回調(diào)
? ? reason = undefined
? ? // 收集函數(shù)狀態(tài)為成功的回調(diào)函數(shù)
? ? successCallback = []
? ? // 收集函數(shù)狀態(tài)為失敗的回調(diào)函數(shù)
? ? failCallback = []
? ? // 執(zhí)行器成功函數(shù)
? ? resolve = value => {
? ? ? ? // 函數(shù)狀態(tài)更改后不可改變 若函數(shù)狀態(tài)不為等待 拒絕向下執(zhí)行
? ? ? ? if (this.status !== PENDING) return
? ? ? ? // 將函數(shù)狀態(tài)更改為成功
? ? ? ? this.status = FULFILLED
? ? ? ? // 成功后的返回值
? ? ? ? this.value = value
? ? ? ? // Promise函數(shù)具有thenable接口且可以多次調(diào)用 導(dǎo)致可能會(huì)有多個(gè)回調(diào)函數(shù)執(zhí)行
? ? ? ? // 使用while循環(huán)是因?yàn)閿?shù)組變化導(dǎo)致循環(huán)體不成立時(shí)自動(dòng)停止
? ? ? ? while (this.successCallback.length) this.successCallback.shift()()
? ? }
? ? // 執(zhí)行器失敗函數(shù)
? ? reject = reason => {
? ? ? ? // 函數(shù)狀態(tài)更改后不可改變 若函數(shù)狀態(tài)不為等待 拒絕向下執(zhí)行
? ? ? ? if (this.status !== PENDING) return
? ? ? ? // 將函數(shù)狀態(tài)更改為失敗
? ? ? ? this.status = REJECTED
? ? ? ? // 失敗后的返回值
? ? ? ? this.reason = reason
? ? ? ? // Promise函數(shù)具有thenable接口且可以多次調(diào)用 導(dǎo)致可能會(huì)有多個(gè)回調(diào)函數(shù)執(zhí)行
? ? ? ? // 使用while循環(huán)是因?yàn)閿?shù)組變化導(dǎo)致循環(huán)體不成立時(shí)自動(dòng)停止
? ? ? ? while (this.failCallback.length) this.failCallback.shift()()
? ? }
? ? // 類的thenable接口
? ? then(successCallback, failCallback) {
? ? ? ? // then方法具有thenable接口 可以鏈?zhǔn)秸{(diào)用 需要返回一個(gè)promise對(duì)象
? ? ? ? // 創(chuàng)建Promise對(duì)象
? ? ? ? let promise = new MyPromise((resolve, reject) => {
? ? ? ? ? ? // then函數(shù)的狀態(tài)取決于回調(diào)函數(shù)運(yùn)行狀態(tài) 現(xiàn)在判斷狀態(tài)
? ? ? ? ? ? if (this.status === FULFILLED) {
? ? ? ? ? ? ? ? // 狀態(tài)為成功
? ? ? ? ? ? ? ? // 在此邏輯中我們會(huì)用到變量promise 為確定變量promise有值 必須確定new MyPromise執(zhí)行完畢
? ? ? ? ? ? ? ? // 故我們使用定時(shí)器setTimeout 不是為了延遲而是為了異步執(zhí)行以確定變量promise有值
? ? ? ? ? ? ? ? setTimeout(() => {
? ? ? ? ? ? ? ? ? ? // 使用trycatch是為了捕獲函數(shù)中的運(yùn)行異常 如出現(xiàn)異常則執(zhí)行catch邏輯 將Promise類的函數(shù)狀態(tài)更改為rejected并將失敗原因返回
? ? ? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? ? ? let result = successCallback(this.value)
? ? ? ? ? ? ? ? ? ? ? ? // result的值可能存在兩種情況普通值和promise對(duì)象
? ? ? ? ? ? ? ? ? ? ? ? // 如果為普通值直接調(diào)用resolve返回
? ? ? ? ? ? ? ? ? ? ? ? // 如果為promise對(duì)象則根據(jù)promise的執(zhí)行結(jié)果決定調(diào)用resolve還是reject
? ? ? ? ? ? ? ? ? ? ? ? // 并且then方法返回的promise對(duì)象不能是當(dāng)前then方法返回的對(duì)象, 否則會(huì)產(chǎn)生Promise對(duì)象的循環(huán)調(diào)用, JS會(huì)報(bào)錯(cuò)
? ? ? ? ? ? ? ? ? ? ? ? // 此邏輯我們用一個(gè)函數(shù)來(lái)實(shí)現(xiàn) 因此我們需要傳入四個(gè)參數(shù)
? ? ? ? ? ? ? ? ? ? ? ? // 1. then方法返回值promise 2. then方法成功回調(diào)的返回值 3. 更改狀態(tài)為成功resolve 4. 更改狀態(tài)為失敗reject
? ? ? ? ? ? ? ? ? ? ? ? resolvePromise(promise, result, resolve, reject)
? ? ? ? ? ? ? ? ? ? } catch (error) {
? ? ? ? ? ? ? ? ? ? ? ? // 捕獲函數(shù)異常 將Promise類的函數(shù)狀態(tài)更改為rejected并將失敗原因返回
? ? ? ? ? ? ? ? ? ? ? ? reject(error)
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }, 0)
? ? ? ? ? ? } else if (this.status === REJECTED) {
? ? ? ? ? ? ? ? // 狀態(tài)為失敗
? ? ? ? ? ? ? ? // 在此邏輯中我們會(huì)用到變量promise 為確定變量promise有值 必須確定new MyPromise執(zhí)行完畢
? ? ? ? ? ? ? ? // 故我們使用定時(shí)器setTimeout 不是為了延遲而是為了異步執(zhí)行以確定變量promise有值
? ? ? ? ? ? ? ? setTimeout(() => {
? ? ? ? ? ? ? ? ? ? // 使用trycatch是為了捕獲函數(shù)中的運(yùn)行異常 如出現(xiàn)異常則執(zhí)行catch邏輯 將Promise類的函數(shù)狀態(tài)更改為rejected并將失敗原因返回
? ? ? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? ? ? let result = failCallback(this.value)
? ? ? ? ? ? ? ? ? ? ? ? // result的值可能存在兩種情況普通值和promise對(duì)象
? ? ? ? ? ? ? ? ? ? ? ? // 如果為普通值直接調(diào)用resolve返回
? ? ? ? ? ? ? ? ? ? ? ? // 如果為promise對(duì)象則根據(jù)promise的執(zhí)行結(jié)果決定調(diào)用resolve還是reject
? ? ? ? ? ? ? ? ? ? ? ? // 并且then方法返回的promise對(duì)象不能是當(dāng)前then方法返回的對(duì)象, 否則會(huì)產(chǎn)生Promise對(duì)象的循環(huán)調(diào)用, JS會(huì)報(bào)錯(cuò)
? ? ? ? ? ? ? ? ? ? ? ? // 此邏輯我們用一個(gè)函數(shù)來(lái)實(shí)現(xiàn) 因此我們需要傳入四個(gè)參數(shù)
? ? ? ? ? ? ? ? ? ? ? ? // 1. then方法返回值promise 2. then方法成功回調(diào)的返回值 3. 更改狀態(tài)為成功resolve 4. 更改狀態(tài)為失敗reject
? ? ? ? ? ? ? ? ? ? ? ? resolvePromise(promise, result, resolve, reject)
? ? ? ? ? ? ? ? ? ? } catch (error) {
? ? ? ? ? ? ? ? ? ? ? ? // 捕獲函數(shù)異常 將Promise類的函數(shù)狀態(tài)更改為rejected并將失敗原因返回
? ? ? ? ? ? ? ? ? ? ? ? reject(error)
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }, 0)
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? // 狀態(tài)為等待
? ? ? ? ? ? ? ? // 此時(shí)需要等待then方法執(zhí)行完畢才能直到函數(shù)狀態(tài)
? ? ? ? ? ? ? ? // 故將成功回調(diào)和失敗回調(diào)存儲(chǔ)起來(lái) 待狀態(tài)更改之后在調(diào)用
? ? ? ? ? ? ? ? this.successCallback.push(() => {
? ? ? ? ? ? ? ? ? ? // 在此邏輯中我們會(huì)用到變量promise 為確定變量promise有值 必須確定new MyPromise執(zhí)行完畢
? ? ? ? ? ? ? ? ? ? // 故我們使用定時(shí)器setTimeout 不是為了延遲而是為了異步執(zhí)行以確定變量promise有值
? ? ? ? ? ? ? ? ? ? setTimeout(() => {
? ? ? ? ? ? ? ? ? ? ? ? // 使用trycatch是為了捕獲函數(shù)中的運(yùn)行異常 如出現(xiàn)異常則執(zhí)行catch邏輯 將Promise類的函數(shù)狀態(tài)更改為rejected并將失敗原因返回
? ? ? ? ? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? ? ? ? ? let result = successCallback(this.value)
? ? ? ? ? ? ? ? ? ? ? ? ? ? // result的值可能存在兩種情況普通值和promise對(duì)象
? ? ? ? ? ? ? ? ? ? ? ? ? ? // 如果為普通值直接調(diào)用resolve返回
? ? ? ? ? ? ? ? ? ? ? ? ? ? // 如果為promise對(duì)象則根據(jù)promise的執(zhí)行結(jié)果決定調(diào)用resolve還是reject
? ? ? ? ? ? ? ? ? ? ? ? ? ? // 并且then方法返回的promise對(duì)象不能是當(dāng)前then方法返回的對(duì)象, 否則會(huì)產(chǎn)生Promise對(duì)象的循環(huán)調(diào)用, JS會(huì)報(bào)錯(cuò)
? ? ? ? ? ? ? ? ? ? ? ? ? ? // 此邏輯我們用一個(gè)函數(shù)來(lái)實(shí)現(xiàn) 因此我們需要傳入四個(gè)參數(shù)
? ? ? ? ? ? ? ? ? ? ? ? ? ? // 1. then方法返回值promise 2. then方法成功回調(diào)的返回值 3. 更改狀態(tài)為成功resolve 4. 更改狀態(tài)為失敗reject
? ? ? ? ? ? ? ? ? ? ? ? ? ? resolvePromise(promise, result, resolve, reject)
? ? ? ? ? ? ? ? ? ? ? ? } catch (error) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? // 捕獲函數(shù)異常 將Promise類的函數(shù)狀態(tài)更改為rejected并將失敗原因返回
? ? ? ? ? ? ? ? ? ? ? ? ? ? reject(error)
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? }, 0)
? ? ? ? ? ? ? ? })
? ? ? ? ? ? ? ? this.failCallback.push(() => {
? ? ? ? ? ? ? ? ? ? // 在此邏輯中我們會(huì)用到變量promise 為確定變量promise有值 必須確定new MyPromise執(zhí)行完畢
? ? ? ? ? ? ? ? ? ? // 故我們使用定時(shí)器setTimeout 不是為了延遲而是為了異步執(zhí)行以確定變量promise有值
? ? ? ? ? ? ? ? ? ? setTimeout(() => {
? ? ? ? ? ? ? ? ? ? ? ? // 使用trycatch是為了捕獲函數(shù)中的運(yùn)行異常 如出現(xiàn)異常則執(zhí)行catch邏輯 將Promise類的函數(shù)狀態(tài)更改為rejected并將失敗原因返回
? ? ? ? ? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? ? ? ? ? let result = failCallback(this.value)
? ? ? ? ? ? ? ? ? ? ? ? ? ? // result的值可能存在兩種情況普通值和promise對(duì)象
? ? ? ? ? ? ? ? ? ? ? ? ? ? // 如果為普通值直接調(diào)用resolve返回
? ? ? ? ? ? ? ? ? ? ? ? ? ? // 如果為promise對(duì)象則根據(jù)promise的執(zhí)行結(jié)果決定調(diào)用resolve還是reject
? ? ? ? ? ? ? ? ? ? ? ? ? ? // 并且then方法返回的promise對(duì)象不能是當(dāng)前then方法返回的對(duì)象, 否則會(huì)產(chǎn)生Promise對(duì)象的循環(huán)調(diào)用, JS會(huì)報(bào)錯(cuò)
? ? ? ? ? ? ? ? ? ? ? ? ? ? // 此邏輯我們用一個(gè)函數(shù)來(lái)實(shí)現(xiàn) 因此我們需要傳入四個(gè)參數(shù)
? ? ? ? ? ? ? ? ? ? ? ? ? ? // 1. then方法返回值promise 2. then方法成功回調(diào)的返回值 3. 更改狀態(tài)為成功resolve 4. 更改狀態(tài)為失敗reject
? ? ? ? ? ? ? ? ? ? ? ? ? ? resolvePromise(promise, result, resolve, reject)
? ? ? ? ? ? ? ? ? ? ? ? } catch (error) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? // 捕獲函數(shù)異常 將Promise類的函數(shù)狀態(tài)更改為rejected并將失敗原因返回
? ? ? ? ? ? ? ? ? ? ? ? ? ? reject(error)
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? }, 0)
? ? ? ? ? ? ? ? })
? ? ? ? ? ? }
? ? ? ? })
? ? ? ? // 返回then函數(shù)的promise對(duì)象
? ? ? ? return promise
? ? }
? ? // 類的finally方法 參數(shù)為回調(diào)函數(shù)
? ? // finally方法的內(nèi)容都會(huì)被執(zhí)行一次
? ? // finally方法之后可以鏈?zhǔn)秸{(diào)用then方法
? ? finally(callback) {
? ? ? ? // 在finally 內(nèi)部可以通過(guò)then方法拿到 當(dāng)前promise的狀態(tài)
? ? ? ? // 并且then方法返回promise對(duì)象 可以鏈?zhǔn)秸{(diào)用then方法
? ? ? ? return this.then(value => {
? ? ? ? ? ? // 如果finally的回調(diào)函數(shù)是promise 需等待回調(diào)函數(shù)執(zhí)行完成在將結(jié)果返回給之后的鏈?zhǔn)秸{(diào)用
? ? ? ? ? ? return MyProise.resolve(callback()).then(() => value)
? ? ? ? }, reason => {
? ? ? ? ? ? // 如果finally的回調(diào)函數(shù)是promise 需等待回調(diào)函數(shù)執(zhí)行完成在將結(jié)果返回給之后的鏈?zhǔn)秸{(diào)用
? ? ? ? ? ? return MyProise.resolve(callback()).then(() => {throw reason})
? ? ? ? })
? ? }
? ? // 捕獲異常
? ? catch(failCallback){
? ? ? ? // 使用then方法去注冊(cè)失敗回調(diào) 并置空成功回調(diào)
? ? ? ? return this.then(undefined, failCallback)
? ? }
? ? // promise.all()方法 參數(shù)為數(shù)組 返回結(jié)果為數(shù)組內(nèi)的元素順序(且為promise對(duì)象), 不論有無(wú)延遲
? ? // 解決異步并發(fā)問(wèn)題
? ? static all(array){
? ? ? ? // 聲明結(jié)果數(shù)組 作為all方法的返回值
? ? ? ? let result = []
? ? ? ? // all方法中有可能有promise的異步操作, 為保證參數(shù)數(shù)組中每一項(xiàng)都有返回值 需對(duì)返回結(jié)果修改時(shí)進(jìn)行標(biāo)記(累加處理)
? ? ? ? let index = 0
? ? ? ? return new MyProise((resolve, reject) => {
? ? ? ? ? ? // 將結(jié)果放入結(jié)果數(shù)組
? ? ? ? ? ? function addData(key, value){
? ? ? ? ? ? ? ? result[key] = value
? ? ? ? ? ? ? ? // 累加處理
? ? ? ? ? ? ? ? index++
? ? ? ? ? ? ? ? // 當(dāng)所有結(jié)果都有返回值時(shí) 執(zhí)行all方法的成功回調(diào)
? ? ? ? ? ? ? ? if(index === array.length){
? ? ? ? ? ? ? ? ? ? resolve(result)
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? // 遍歷當(dāng)前數(shù)組 并且判斷循環(huán)體是普通值還是promise對(duì)象
? ? ? ? ? ? for(let i = 0; i < array.length; i++){
? ? ? ? ? ? ? ? // 劫持循環(huán)體
? ? ? ? ? ? ? ? let current = array[i]
? ? ? ? ? ? ? ? if(current instanceof MyProise){
? ? ? ? ? ? ? ? ? ? // 循環(huán)體為promise對(duì)象 根據(jù)其運(yùn)行結(jié)果調(diào)用resolve和reject更改狀態(tài)
? ? ? ? ? ? ? ? ? ? current.then(value => addData(i, value), reason => reject(reason))
? ? ? ? ? ? ? ? }else {
? ? ? ? ? ? ? ? ? ? // 循環(huán)體為普通值
? ? ? ? ? ? ? ? ? ? addData(i, current)
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? })
? ? }
? ? // Promise.resolve()方法返回一個(gè)promise對(duì)象
? ? static resolve (value){
? ? ? ? // 如果value是promise對(duì)象直接返回
? ? ? ? if(value instanceof MyProise) return value
? ? ? ? // 如果value是普通值 返回一個(gè)promise對(duì)象 并且將value當(dāng)作成功返回值返回
? ? ? ? return new MyProise(resolve => resolve(value))
? ? }
}
function resolvePromise(promise, result, resolve, reject) {
? ? // 如果then方法返回值promise 和 then方法成功回調(diào)的返回值 相同
? ? if (promise === result) {
? ? ? ? // 拋出錯(cuò)誤 promise對(duì)象循環(huán)調(diào)用
? ? ? ? return reject(new TypeError('TypeError: Chaining cycle detected for promise #<Promise>'))
? ? }
? ? // 如果then方法成功回調(diào)的返回值 是promise對(duì)象
? ? if (result instanceof MyProise) {
? ? ? ? // 調(diào)用promise對(duì)象的then方法 根據(jù)執(zhí)行結(jié)果決定調(diào)用resolve還是reject
? ? ? ? result.then(resolve, reject)
? ? } else {
? ? ? ? // 如果then方法成功回調(diào)的返回值 是普通值
? ? ? ? resolve(result)
? ? }
}