Open
Description
概要
promise
的使用现在已经非常普及了。 虽然方便了开发者,但是也带了一些八股文考题,常见的就是如何实现一个promise
. 下边从零开始,一步步实现一个完整的promise
。
简易版分析
简易版的promise
应该具有以下基础功能:
- 新建
promise
; promise
状态正常流转;then
方法;
简单实现
状态管理
首先,一个promise
具有三个状态pending
、fulfilled
、rejected
。且只能按照如下方式流转
pending
--->fulfilled
pending
--->rejected
状态一旦改变,就不再变了。
其次,创建Promise
的时候,接受一个函数,且会立即执行,该函数接受两个函数参数,resolve
,reject
,用来改变状态;
基于此可以实现如下代码
// 先定义三个状态变量
const PENDING = 'pending'
const REJECTED = 'rejected'
const FULFILLED = 'fulfilled'
class MyPromise {
state = PENDING
value = '' // 向后传的value值
constructor(fn) {
if (typeof fn !== "function") {
throw new Error('参数必须是函数')
}
fn(this._resolve.bind(this), this._reject.bind(this))
}
_resolve(value) {
this.state = FULFILLED //修改状态
this.value = value // 赋值,用于向后传递
}
_reject(error) {
this.state = REJECTED //修改状态
this.value = error // 赋值,用于向后传递
}
}
then
then
是promise
的一个基本且强大方法,具有以下特点
- 接受两个函数参数
onFulfilled
,onRejected
;分别承接resolve
和reject
的回调; then
方法会返回一个新的promise
,因此可以实现链式调用,一直then
下去;
实现then
的一个难点就是,每次then
方法会注册两个函数参数onFulfilled
, onRejected
,但是具体执行哪一个,依赖前一个promise
的状态,fulfilled
状态时调用onFulfilled
,rejected
状态时调用onRejected
。 因此onFulfilled
, onRejected
必须注册在前一个promise的回调队列中,以便状态变更时,正确回调;
基于以上分析,完善代码如下
// 先定义三个状态变量
const PENDING = 'pending'
const REJECTED = 'rejected'
const FULFILLED = 'fulfilled'
class MyPromise {
state = PENDING
value = '' // 向后传的value值
callbacks = [] // 回调队列
constructor(fn) {
if (typeof fn !== "function") {
throw new Error('参数必须是函数')
}
fn(this._resolve.bind(this), this._reject.bind(this))
}
then(onFulfilled, onRejected) {
const _this = this; // _this指向前一个promise对象,这个很关键
return new MyPromise((resolve, reject) => {
_this._handle({
onFulfilled,
onRejected,
resolve,
reject
})
})
}
_resolve(value) {
if (this.state !== PENDING) {
return
}
this.state = FULFILLED // 修改状态
this.value = value // 赋值,用于向后传递
this.callbacks.forEach(cb => this._handle(cb)) //回调then中的注册函数
}
_reject(error) {
if (this.state !== PENDING) {
return
}
this.state = REJECTED // 修改状态
this.value = error // 赋值,用于向后传递
this.callbacks.forEach(cb => this._handle(cb)) //回调then中的注册函数
}
_handle(callback) {
// pending状态时,注册函数入栈
if (this.state === PENDING) {
this.callbacks.push(callback)
return
}
// 按需获取then中注册的回调函数
const cb = this.state === FULFILLED ? callback.onFulfilled : callback.onRejected
// 改变then返回的promise的状态,持续回调后续的then
const cb_changeState = this.state === FULFILLED ? callback.resolve : callback.reject
let ret
if (cb) {
ret = cb(this.value) // 计算继续向后传递的值
}
cb_changeState(ret)
}
}
demo
new MyPromise((resolve, reject) => {
resolve('test')
}).then((value) => {
console.log('then1', value)
}, (err) => {
console.log('reject1', err)
}).then((value) => {
console.log('then2', value)
}, (err) => {
console.log('reject2', err)
})
最终输出如下:
then1,test
then2,undefined
遗留问题
上述代码虽然实现了状态变化以及链式调用等基本能力,但是会存在一个很大的问题,第一个promise
的状态变为fulfilled
,那么会依次调用后续的onFulfilled
函数。这是不符合预期的。
预期是当前then
的回调函数,只取决于前一个promise
的状态,即整个回调链路中可能同时存在onFulfilled
,onRejected
。
在下一篇文章中将专门解决这个问题。
参考文献
Metadata
Metadata
Assignees
Labels
No labels