最近在使用ES6,所以手動實現(xiàn)了一個簡單的ES6 Promise對象來玩玩(如果有錯誤的地方,希望大家能夠不吝賜教)
一個
promise對象接收的是一個callback
這個callback接收兩個參數(shù)(resolve,reject)
當(dāng)我們在callback內(nèi)執(zhí)行resolve或reject的時候,就會調(diào)用Promise內(nèi)定義的resolve和reject函數(shù)
然后,resolve和reject函數(shù)會改變Promise的狀態(tài)
所以它應(yīng)該是像下面這樣的
function MyPromise(callback) {
// 保存this值
var self = this
// 記錄狀態(tài)null為pending,true為resolved,false為reject
var state = null
// 記錄resolve的參數(shù)
var param = null
// 執(zhí)行傳入的callback并改變promise對象狀態(tài)
callback(resolve, reject)
// resolve方法
function resolve(data) {
// 改變狀態(tài)
state = true
param = data
}
// reject方法
function reject(err) {
state = false
param = err
}
}
但沒有
then方法的Promise對象是不完整的(完全沒有用)
所以我們需要一個then方法,要記住then方法返回的也是一個promise對象
then方法接收兩個可選的參數(shù)(onFulfilled, onRejected)(我們可以先忽略可選兩個字)
then方法傳進(jìn)來的參數(shù)必須是函數(shù),如果不是就要忽略(PromiseA+規(guī)范)(我們可以也先忽略這句話)
this.then = function (onFulfilled, onRejected) {
// 返回一個新的promise對象
return new self.constructor(function (resolve, reject) {
// then
})
}
接下來就是
then方法的具體實現(xiàn)了
then方法中onFulfilled, onRejected的返回值會作為新promise的執(zhí)行結(jié)果
onFulfilled, onRejected這兩個函數(shù)要在promise的狀態(tài)變?yōu)閜ending或resolved的時候才能分別執(zhí)行
所以如果promise方法狀態(tài)為resolved或rejected的話,我們就可以直接在then方法中執(zhí)行resolve(onFulfilled(param))和reject(onRejected(param))
this.then = function (onFulfilled, onRejected) {
// 返回一個新的promise對象
return new self.constructor(function (resolve, reject) {
if (state === true) {
// param是promise對象完成后的結(jié)果
resolve(onFulfilled(param))
} else if (state === false) {
reject(onRejected(param))
} else {
// 沒有執(zhí)行完畢,怎么辦
}
})
}
但如果
promise的狀態(tài)為pending呢
由于原始promise的狀態(tài)我們是無法動態(tài)獲取的,因此我們就需要在他執(zhí)行狀態(tài)改變的時候同時執(zhí)行onFulfilled和onRejected方法
我們可以把這個方法放在原始promise對象的resolve和reject方法中執(zhí)行
因此我們要在promise的對象定義中添加四個參數(shù),分別記錄onFulfilled和onRejected,以及then方法返回的新promise對象的resolve和reject
然后如果執(zhí)行then方法的時候promise對象的狀態(tài)為pending的話,就將上述四個參數(shù)記錄起來
// then方法返回的promise對象的resolve和reject
var nextResolve = null
var nextReject = null
// 記錄then方法的參數(shù),onFulfilled和onRejected
var asynconFulfilled = null
var asynconRejected = null
//then方法
this.then = function (onFulfilled, onRejected) {
// 返回一個新的promise對象
return new self.constructor(function (resolve, reject) {
if (state === true) {
// param是promise對象完成后的結(jié)果
resolve(onFulfilled(param))
} else if (state === false) {
reject(onRejected(param))
} else {
nextResolve = resolve
nextReject = reject
asynconFulfilled = onFulfilled
asynconRejected = onRejected
}
})
}
接下來就是原始
promise中的resolve和reject的重新實現(xiàn)
// resolve方法
function resolve(data) {
// 改變狀態(tài)
state = true
param = data
nextResolve(asynconFulfilled(param))
}
// reject方法
function reject(err) {
state = false
param = err
nextReject(asynconRejected(param))
}
很簡單不是嗎
我們繼續(xù)
上述實現(xiàn)我們一直沒有考慮一個很重要的情況,如果then方法返回的還是一個promise對象,那么如果我們后邊還有then方法的話就要等待前一個then方法中的promise對象的狀態(tài)從pending變?yōu)橥瓿?br> 這要怎么做呢
什么時候可以認(rèn)為then方法返回的promise對象執(zhí)行完畢了呢,這里我們就要用到then方法(@_@,邊寫邊用...),
以resolve方法為例
var self = this
// resolve方法
function resolve(data) {
// 記錄onFulfilled的執(zhí)行結(jié)果
let parmise
// 改變狀態(tài)
state = true
param = data
// 執(zhí)行記錄的onFulfilled
parmise = asynconFulfilled(param)
if(parmise === undefined){
// 如果parmise為undefined,就不能解析parmise.constructor
} else if (parmise.constructor === self.constructor) {
// 等待傳遞進(jìn)來的promise對象執(zhí)行完畢,然后根據(jù)傳遞進(jìn)來的promise對象的狀態(tài)執(zhí)行resolve或reject
// 注意,這個param是形參,在then方法的promise中執(zhí)行
promise.then(function (param) {
resolve(param)
}, function (param) {
reject(param)
})
} else {
// 這個是前邊的then返回的不是promise對象的情況
resolve(promise)
}
}
前面我們忽略了兩點 (
then方法接收兩個可選的參數(shù)(onFulfilled, onRejected)) 和 (then方法傳進(jìn)來的參數(shù)必須是函數(shù),如果不是就要忽略)
var self = this
// resolve方法
function resolve(data) {
// 記錄onFulfilled的執(zhí)行結(jié)果
var parmise
// 改變狀態(tài)
state = true
param = data
// 執(zhí)行記錄的onFulfilled
// begin--------------
if (typeof onFulfilled === 'function') {
promise = onFulfilled(param)
if (promise === undefined) {
// 待補充
} else if (promise.constructor === self.constructor) {
// 注意,這個param是形參,在then方法的promise中執(zhí)行
promise.then(function (param) {
resolve(param)
}, function (param) {
reject(param)
})
} else {
reject(promise)
}
} else {
// 如果onFulfilled不是function,忽略,直接resolve或reject
resolve(param)
}
// ---------------end
}
上面begin到end之間的代碼還要在
then方法調(diào)用,所以我們可以把這段代碼抽象為一個函數(shù)
resolve和reject的原理相同,只要注意如果不是function 的話需要執(zhí)行reject
onFulfilled和onRejected只有在[執(zhí)行環(huán)境]堆棧僅包含平臺代碼時才可被調(diào)用
所以將上述begin-end之間的代碼放到seTimeout中執(zhí)行(瀏覽器環(huán)境)
function resolve(data) {
// 記錄onFulfilled的執(zhí)行結(jié)果
var parmise
// 改變狀態(tài)
state = true
param = data
// 執(zhí)行記錄的onFulfilled
window.setTimeout(function () {
// begin--------------
// 上述代碼
// ---------------end
}, 0)
}
下面是完整代碼
// 簡單實現(xiàn)ES6 Promise
function MyPromise(callback) {
// 保存this值
var self = this
// 記錄狀態(tài)null為pending,true為resolved,false為reject
var state = null
// 記錄resolve的參數(shù)
var param = null
// then方法返回的promise對象的resolve和reject
var nextResolve = null
var nextReject = null
// 記錄then方法的參數(shù),onFulfilled和onRejected
var asynconFulfilled = null
var asynconRejected = null
// 執(zhí)行并改變promise對象狀態(tài)
callback(resolve, reject)
// then方法
this.then = function (onFulfilled, onRejected) {
// 返回一個新的promise對象
return new self.constructor(function (resolve, reject) {
// 判斷異步代碼是否執(zhí)行完畢(是否resolve或reject)
// 若執(zhí)行完畢就在then方法中立即執(zhí)行,否則將四個參數(shù)記錄下來,等待state就緒后再執(zhí)行doAsyn*函數(shù)
if (state === true) {
doAsynconFulfilled(onFulfilled, resolve, reject)
} else if (state === false) {
doAsynconRejected(onRejected, resolve, reject)
} else {
nextResolve = resolve
nextReject = reject
asynconFulfilled = onFulfilled
asynconRejected = onRejected
}
})
}
// resolve方法
function resolve(data) {
// 改變狀態(tài)
state = true
param = data
if(nextResolve){
doAsynconFulfilled(asynconFulfilled, nextResolve, nextReject)
}
}
// reject方法
function reject(err) {
state = false
param = err
if(nextReject){
doAsynconRejected(asynconRejected, nextResolve, nextReject)
}
}
// 核心方法(我覺得是)
function doAsynconFulfilled(onFulfilled, resolve, reject) {
window.setTimeout(function () {
// 判斷onFulfilled是否為function,不是則忽略
if (typeof onFulfilled === 'function') {
// 執(zhí)行onFulfilled方法獲取返回值promise()
let promise = onFulfilled(param)
// 如果promise為undefined 執(zhí)行 if
// 如果promise為MyPromise對象 執(zhí)行 else if
// 如果promise為非MyPromise對象 執(zhí)行 else
if (promise === undefined) {
resolve(param)
// 待補充
} else if (promise.constructor === self.constructor) {
// 等待傳遞進(jìn)來的promise對象執(zhí)行完畢,然后根據(jù)傳遞進(jìn)來的promise對象的狀態(tài)執(zhí)行resolve或reject
promise.then(function (param) {
resolve(param)
}, function (param) {
reject(param)
})
} else {
// 執(zhí)行then方法返回的對象的resolve
resolve(promise)
}
} else {
// 傳遞參數(shù)
resolve(param)
}
}, 0)
}
function doAsynconRejected(onRejected, resolve, reject) {
window.setTimeout(function () {
if (typeof onRejected === 'function') {
let promise = onRejected(param)
if (promise === undefined) {
reject(param)
// 待補充
} else if (promise.constructor === self.constructor) {
promise.then(function (param) {
resolve(param)
}, function (param) {
reject(param)
})
} else {
reject(promise)
}
} else {
// 傳遞錯誤信息
reject(param)
}
}, 0)
}
}
// 測試使用
var b = function (message) {
return new MyPromise(function (resolve, reject) {
document.body.onclick = function () {
resolve('click:' + message)
}
})
}
var a = new MyPromise(function (resolve, reject) {
resolve(123)
}).then(function (message) {
return b(message)
}).then().then(function (message) {
console.log('final:' + message)
},function (err) {
console.log('final:' + err)
})
console.log('window')
完畢!