做者:@gauseen前端
Promises/A+
規範可在這裏查看git
promise
有 3
個狀態,分別爲 pending
, fulfilled
和 rejected
github
promise 在 pending
狀態promise
fulfilled
或 rejected
狀態promise 在 fulfilled
狀態異步
promise 在 rejected
狀態函數
// promise 三種狀態 const PENDING = 'pending' const FULFILLED = 'fulfilled' const REJECTED = 'rejected' // MyPromise 構造函數 function MyPromise (fn) { // 初始化狀態 this.state = PENDING this.result = void 0 this.handlerQueue = [] let resolve = (value) => { transitionState(this, FULFILLED, value) } let reject = (reason) => { transitionState(this, REJECTED, reason) } // 調用 Promise 構造函數回調 try { fn(resolve, reject) } catch (error) { reject(error) } }
狀態遷移方法,即調用了 fn(resolve, reject)
中的 resolve, reject
方法後,須要改變 promise
狀態:this
pending --> fulfilled
spa
pending --> rejected
prototype
function transitionState (promise, state, result) { if (promise.state !== PENDING) return promise.state = state promise.result = result // 這裏先佔個坑位 }
then
方法返回的是一個新的 Promise
實例(注意:不是原來那個 Promise
實例),只有這樣才能不斷的鏈式調用,依次改變狀態code
MyPromise.prototype.then = function (onFulfilled, onRejected) { return new MyPromise((resolve, reject) => { let handler = { onFulfilled, onRejected, resolve, reject } // 若當前狀態爲 pending 則將其放在 handlerQueue 隊列中,等待 resolve 或 reject 方法改變其狀態 // 不然直接調用 then 方法中的 resolve 或 reject 回調函數 if (this.state ==== PENDING) { this.handlerQueue.push(handler) } else { dispatchHandler(handler, this.state, this.result) } }) }
const isFunction = arg => typeof arg === 'function' function dispatchHandler (handler, state, result) { let { onFulfilled, onRejected, resolve, reject } = handler if (state === FULFILLED) { let finalValue = isFunction(onFulfilled) ? onFulfilled(result) : result resolve(finalValue) } else if (state === REJECTED) { let finalReason = isFunction(onRejected) ? onRejected(result) : result reject(finalReason) } }
以上代碼,只支持 Promise 回調函數參數 resolve
和 reject
同步調用的狀況,以下示例代碼:
// 支持 let myPromise = new MyPromise((resolve, reject) => { // resolve 同步調用 resolve('同步調用 value') }) myPromise.then((value) => { console.log('value: ', value) }, (reason) => { console.log('reason: ', reason) })
可是,使用異步調用不支持,以下示例代碼:
// 暫不支持 let myPromise = new MyPromise((resolve, reject) => { // resolve 異步調用 setTimeout(() => { resolve('異步調用 value') }) }) myPromise.then((value) => { console.log('value: ', value) }, (reason) => { console.log('reason: ', reason) })
之因此不支持異步調用 resolve 或 reject
,是由於 then
方法中以下代碼片斷:
// 當 resolve 爲異步調用,then 方法執行時,promise 狀態爲 pending。 // 因此 then 回調函數 onFulfilled 和 onRejected 在 handlerQueue 隊列裏,沒有被調用 if (this.state ==== PENDING) { this.handlerQueue.push(handler) } else { // ... }
爲支持 resolve
、reject
異步調用,狀態遷移方法 transitionState
,作以下修改:
function transitionState (promise, state, result) { if (promise.state !== PENDING) return promise.state = state promise.result = result // 新增代碼開始 promise.handlerQueue.forEach(handler => { dispatchHandler(handler, state, result) }) // 新增代碼結束 }
由於 catch
方法是 .then(null, onRejected)
的別名,因此實現 catch
代碼以下:
MyPromise.prototype.catch = function (onRejected) { return this.then(null, onRejected) }
如上,簡單實現了 promise
,支持鏈式調用 then 和 catch
歡迎關注無廣告文章公衆號:學前端