作者:@gauseen
Promises/A+
規範可在這裏查看
promise
有 3
個狀態,分別爲 pending
, fulfilled
和 rejected
-
promise 在
pending
狀態- 可以切換到
fulfilled
或rejected
狀態
- 可以切換到
-
promise 在
fulfilled
狀態- 不可以切換到其它狀態
- 必須有個不可以更改的 value 值
-
promise 在
rejected
狀態- 不可以切換到其它狀態
- 必須有個不可以更改的 reason 值
// 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
狀態:
pending --> fulfilled
pending --> rejected
function transitionState (promise, state, result) {
if (promise.state !== PENDING) return
promise.state = state
promise.result = result
// 這裏先佔個坑位
}
then
方法返回的是一個新的 Promise
實例(注意:不是原來那個 Promise
實例),只有這樣才能不斷的鏈式調用,依次改變狀態
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
歡迎關注無廣告文章公衆號:學前端