ES2015提出了Promise
附较,同時(shí)基于Promise
的異步開發(fā)將開發(fā)者中回調(diào)地獄中解救出來眷蜈。但在沒有原生支持的環(huán)境下预厌,需要借助Promise/A+
之類的庫來實(shí)現(xiàn)Promise
,今天就來嘗試自行實(shí)現(xiàn)Promise叨橱。
1 基本實(shí)現(xiàn)
首先來完成一個(gè)Promise
類的基本框架:
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è)問題畦韭,resolve方法會(huì)調(diào)用多次,所以接下來我們需要接入狀態(tài)管理肛跌。
Promise
內(nèi)部存在3個(gè)狀態(tài):
- pending
- resolved
- rejected
接下來在現(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)用据过,但是卻無法實(shí)現(xiàn)鏈?zhǔn)交卣{(diào),原因在于其then
方法沒有返回一個(gè)新的Promise
對(duì)象妒挎,所以接下來還需要改造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ì)象還沒用,接下來我們來寫個(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)用過酝掩,因而其onResolved
onRejected
的回調(diào)ye就無從調(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
})
}
}
接下來還需在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)
}