Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件更合理和更强大。想要实现一个promise,则必须要知道它的特点以及实现原理。
Promise对象有以下两个特点:
- 对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
- 一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
Promise实现原理:
- 创建一个promise对象(该promise下面称作promise1),其状态为padding(进行中),需手动调用resolve或reject方法才会切换状态,状态切换后,会执行相应的fulfilled和rejected(这两个回调存储在promise的deferred数组)。
- 如果回调函数返回的是一个promise对象,则后面的回调函数会存储在返回的promise对象的deferred;如果返回的不是promise,会先判断promise1的状态是否为fulfilled,是,则后面的回调函数存储在promise1的deferred,并且立即执行。不是,则将promise1中deferred数组的promise的状态变为fulfilled,继续执行后面的回调。
- promise1调用then方法,then接受两个参数fulfilled和rejected,并且创建一个promise,然后将fulfilled、rejected、promise存进一个对象里,在将这个对象推入promise1的deferred数组,返回新创建的promise。
懂了实现原理,我们知道实现一个简易的promise,需要有status(状态)、deferred、value(执行fulfilled和rejected回调时传入的参数)三个属性以及then、resolve、reject、done(执行deferred)这四个方法。
resolve和reject的实现:
/**
* 推入microtask( 保证其回调是异步执行)。
* resolve会接受一个value,value会填充promise的value属性。
* 将promise状态变为fulfilled并执行done方法。
*/
resolve(value) {
this.pushMicroTask(() => {
if (this.status !== 'pendding') return
this.status = 'fulfilled'
this.value = value
this.done()
});
}
// 与resolve一样,只是状态变为rejected
reject(value) {
this.pushMicroTask(() => {
if (this.status !== 'pendding') return
this.status = 'rejected'
this.value = value
this.done()
});
}
then的实现
/**
* then方法接收onFulfilled、onRejected两个参数
* 创建新的promise,将onFulfilled、onRejected、新的promise推到deferred
* 返回新创建的promise
*/
then(onFulfilled, onRejected) {
const promise = new CreatPromise()
const item = {
onFulfilled,
onRejected,
promise
}
this.deferred.push(item)
// promise状态不为padding,则立即执行回调
if (this.status === 'fulfilled' || this.status === 'rejected') {
this.pushMicroTask(this.done.bind(this))
}
return promise
}
done的实现
done() {
if (this.status === 'pendding' || this.deferred.length === 0) return
const _deferred = this.deferred
// 清空deferred
this.deferred = []
for (let i of _deferred) {
let { success, fail, promise } = i
let _promise
/**
* 执行回调,如果回调函数有报错,则promise状态变为rejected,return,继续处理后面的deferred
*/
if (this.status === 'fulfilled' && success) {
try {
_promise = success(this.value)
} catch(err) {
promise.reject(err)
return
}
} else if (this.status === 'rejected' && fail) {
try {
_promise = fail(this.value)
} catch(err) {
promise.reject(err)
return
}
}
/**
* 如果回调函数返回值是promise实例,则后面的deferred由返回的promise实例来处理
* 返回值不为promise实例分两种情况
* 1.this状态为rejected且有fail函数,则promise状态变为fulfilled.后面的deferred交由promise处理
* 2.this状态为fulfilled或rejected,则后面的deferred还是交由当前promise处理
*/
if (typeof _promise === 'object' && _promise instanceof CreatPromise) {
_promise.deferred = promise.deferred
} else if (this.status === 'rejected' && fail) {
promise.resolve(_promise)
} else if (this.status === 'fulfilled' || this.status === 'rejected') {
this.deferred = this.deferred.concat(promise.deferred)
this.value = _promise || this.value
}
}
// 如果deferred不为空,继续执行
if (this.deferred.length > 0) this.pushMicroTask(this.done.bind(this))
}
完整代码
class CreatPromise {
constructor(callback) {
// 状态初始化
this.status = 'pendding'
this.value = undefined
this.deferred = []
// 调用callback,resolve和reject方法作为参数传入
callback && callback(this.resolve.bind(this), this.reject.bind(this))
}
// 模拟promise微任务(可以用MutationObserver实现,这里展示就没用了)
pushMicroTask (fn) {
setTimeout(() => {
fn()
}, 0);
}
resolve(value) {
this.pushMicroTask(() => {
if (this.status !== 'pendding') return
this.status = 'fulfilled'
this.value = value
this.done()
});
}
reject(value) {
this.pushMicroTask(() => {
if (this.status !== 'pendding') return
this.status = 'rejected'
this.value = value
this.done()
});
}
then(success, fail) {
const promise = new CreatPromise()
// 回调信息
const item = {
success,
fail,
promise
}
this.deferred.push(item)
// 当前promise状态已完成,则立即执行回调
if (this.status === 'fulfilled' || this.status === 'rejected') this.pushMicroTask(this.done.bind(this))
return promise
}
done() {
if (this.status === 'pendding' || this.deferred.length === 0) return
const _deferred = this.deferred
this.deferred = []
for (let i of _deferred) {
let { success, fail, promise } = i
let _promise
/**
* 执行回调,如果回调函数有报错,则promise状态变为rejected,继续处理后面的deferred
*/
if (this.status === 'fulfilled' && success) {
try {
_promise = success(this.value)
} catch(err) {
promise.reject(err)
return
}
} else if (this.status === 'rejected' && fail) {
try {
_promise = fail(this.value)
} catch(err) {
promise.reject(err)
return
}
}
/**
* 如果回调函数返回值是promise实例,则后面的回调信息存于返回的promise实例
* 返回值不为promise实例分两种情况
* 1:当前promise(this)状态为rejected且有fail函数,则promise状态变为fulfilled.后面的deferred交由promise处理
* 2.当前primise(this)状态为fulfilled或rejected,则后面的deferred还是交由当前promise处理
*/
if (typeof _promise === 'object' && _promise instanceof CreatPromise) {
_promise.deferred = promise.deferred
} else if (this.status === 'rejected' && fail) {
promise.resolve(_promise)
} else if (this.status === 'fulfilled' || this.status === 'rejected') {
this.deferred = this.deferred.concat(promise.deferred)
this.value = _promise || this.value
}
}
// 如果deferred不为空,继续执行
if (this.deferred.length > 0) this.pushMicroTask(this.done.bind(this))
}
catch(callback) {
return this.then(null, callback)
}
finally(callback) {
return this.then(callback, callback)
}
}
CreatPromise.resolve = function(value) {
// 如果参数是promise实例,则原封不动返回该实例
if (value instanceof CreatPromise) return value
// 如果参数是个thenable对象,则将这个对象转为 Promise 对象,然后就立即执行thenable对象的then方法。
if (typeof value === 'object' || typeof value === 'function') {
const then = value.then
if (typeof then === 'function') {
return new CreatPromise(then.bind(value))
}
}
return new CreatPromise((resolve) => resolve(value))
}
CreatPromise.reject = function(error) {
// reject与resolve不同,会原封不动地作为reject的理由,变成后续方法的参数
return new CreatPromise((resolve, reject) => reject(error))
}