ES2015提出了Promise
,同时基于Promise
的异步开发将开发者中回调地狱中解救出来。但在没有原生支持的环境下,需要借助Promise/A+
之类的库来实现Promise
,今天就来尝试自行实现Promise。
首先来完成一个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
的基本实现。
上述的代码存在一个问题,resolve方法会调用多次,所以接下来我们需要接入状态管理。
Promise
内部存在3个状态:
接下来在现有代码之上,加入状态管理:
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)
}
上述Promise
实现可以完成正常的异步调用,但是却无法实现链式回调,原因在于其then
方法没有返回一个新的Promise
对象,所以接下来还需要改造then
方法,实现链式调用:
this.then = function(onResolved, onRejected) {
if(state === 'pending') {
resolveCallback = onResolved
rejectCallback = onRejected
}
return new MyPromise((resolve, reject) => {
......
})
}
光返回一个promise
对象还没用,接下来我们来写个demo测试下:
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
事实上,第二个promise对象的resolve
reject
方法从未被调用过,因而其onResolved
onRejected
的回调ye就无从调用。所以还必须指定时机调用字promise
对象的resolve
和reject
。
所以首先需要在创建新promise
对象时,记录其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
方法中调用子对象的resolve
和reject
方法,整个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)
}