ES2015提出了Promise,同時(shí)基于Promise的異步開(kāi)發(fā)將開(kāi)發(fā)者中回調(diào)地獄中解救出來(lái)。但在沒(méi)有原生支持的環(huán)境下,需要借助Promise/A+之類(lèi)的庫(kù)來(lái)實(shí)現(xiàn)Promise,今天就來(lái)嘗試自行實(shí)現(xiàn)Promise。
1 基本實(shí)現(xiàn)
首先來(lái)完成一個(gè)Promise類(lèi)的基本框架:
function Promise(fn) {
var resolveCallback = null
var rejectCallback = null
this.then = function(onResolved, onRejected) {
resolveCallback = onResolved
rejectCallback = onRejected
}
this.resolve = function(value) {
this.resolveCallback(value)
}
this.reject = function(reason) {
this.rejectCallback(reason)
}
fn(this.resolve, this.reject)
}
以上便是Promise的基本實(shí)現(xiàn)。
2 狀態(tài)管理
上述的代碼存在一個(gè)問(wèn)題,resolve方法會(huì)調(diào)用多次,所以接下來(lái)我們需要接入狀態(tài)管理。
Promise內(nèi)部存在3個(gè)狀態(tài):
- pending
- resolved
- rejected
接下來(lái)在現(xiàn)有代碼之上,加入狀態(tài)管理:
function MyPromise(fn) {
let state = 'pending'
var resolveCallback = null
var rejectCallback = null
var childResolve
var childReject
this.then = function(onResolved, onRejected) {
resolveCallback = onResolved
rejectCallback = onRejected
}
this.resolve = function(value) {
if(state === 'pending') {
this.resolveCallback(value)
state = 'resolved'
}
}
this.reject = function(reason) {
if(state === 'pending') {
this.rejectCallback(reason)
state = 'rejected'
}
}
fn(this.resolve, this.reject)
}
3 鏈?zhǔn)秸{(diào)用
上述Promise實(shí)現(xiàn)可以完成正常的異步調(diào)用,但是卻無(wú)法實(shí)現(xiàn)鏈?zhǔn)交卣{(diào),原因在于其then方法沒(méi)有返回一個(gè)新的Promise對(duì)象,所以接下來(lái)還需要改造then方法,實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用:
this.then = function(onResolved, onRejected) {
if(state === 'pending') {
resolveCallback = onResolved
rejectCallback = onRejected
}
return new MyPromise((resolve, reject) => {
......
})
}
光返回一個(gè)promise對(duì)象還沒(méi)用,接下來(lái)我們來(lái)寫(xiě)個(gè)demo測(cè)試下:
var demo = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('my first promise')
}, 1000)
})
demo.then((msg) => {
console.log(msg)
return 'my second promise'
}).then((msg) => {
console.log(msg)
})
其輸出為:
my first promise
事實(shí)上,第二個(gè)promise對(duì)象的resolve reject方法從未被調(diào)用過(guò),因而其onResolved onRejected的回調(diào)ye就無(wú)從調(diào)用。所以還必須指定時(shí)機(jī)調(diào)用字promise對(duì)象的resolve和reject。
所以首先需要在創(chuàng)建新promise對(duì)象時(shí),記錄其resolve和reject方法:
function MyPromise() {
......
var childResolve
var childReject
this.then = function(onResolved, onRejected) {
if(state === 'pending') {
resolveCallback = onResolved
rejectCallback = onRejected
}
return new MyPromise((resolve, reject) => {
childResolve = resolve
childReject = reject
})
}
}
接下來(lái)還需在resolve 和 reject方法中調(diào)用子對(duì)象的resolve和reject方法,整個(gè)Promise完整代碼如下:
function MyPromise(fn) {
let state = 'pending'
var resolveCallback = null
var rejectCallback = null
var childResolve = null
var childReject = null
this.then = function(onResolved, onRejected) {
if(state === 'pending') {
resolveCallback = onResolved
rejectCallback = onRejected
}
return new MyPromise((resolve, reject) => {
childResolve = resolve
childReject = reject
})
}
this.resolve = function(value) {
if(state === 'pending') {
if(resolveCallback) {
var ret = resolveCallback(value)
childResolve(ret)
state = 'resolved'
}
}
}
this.reject = function(reason) {
if(state === 'pending') {
if(rejectCallback) {
var ret = rejectCallback(reason)
childReject(ret)
state = 'rejected'
}
}
}
fn(this.resolve, this.reject)
}