理解Promise
不考虑参照Promises/A+规范,不考虑任何异常情况;主要关注核心逻辑实现一个Promise。
构造一个Promise对象
设想
// Promise构造函数接收一个executor函数,executor函数执行完同步或异步操作后,调用它的两个参数resolve和reject
let promise = new Promise(function(resolve, reject) {
/*
如果操作成功,调用resolve并传入value
如果操作失败,调用reject并传入reason
*/
})
大概思路
实例化时用户传入自定义fn,fn内部会做逻辑判断(成功/失败)。成功/失败修改实例中的对应的属性。
在自定义fn调用时,让成功/失败的方法作为fn参数,用户就可以在fn内部使用成功/失败的方法
JS代码
const STATUS = {
PENDING: 'pending',
RESOLVED: 'resolved',
REJECTED: 'rejected',
}
class MyPromise {
constructor(executor) {
// 被resolved的值
this._value = undefined;
// 被rejected的值
this._reason = undefined;
this._state = STATUS.PENDING;
if (executor) {
// TODO: 简单的异步处理 可优化
setTimeout(() => {
// TODO: executor是用户传入的函数,考虑到执行executor的过程中有可能出错,所以可以考虑try/catch块给包起来
// 执行executor时,bind()保证resolve,reject内部this!=undefined
executor(this._onResolved.bind(this), this._onRejected.bind(this))
})
}
}
_onResolved(value) {
const {_state,} = this
const {PENDING, RESOLVED} = STATUS
if (_state === PENDING) { // 确保_state只会修改一次
this._value = value
this._state = RESOLVED
}
}
_onRejected(reason) {
const {_state, _reason} = this
const {PENDING, REJECTED} = STATUS
if (_state === PENDING) { // 确保_state只会修改一次
this._reason = reason
this._state = REJECTED
}
}
}
实现核心的功能异步链式调用(then)
设想
// 调用then并传入onResolved或onRejected 方法,将return值作为下一个then的onResolved参数,并且then()的返回值是promise。
let promise2 = promise.then(
function(res) {return res }, // 如果操作成功,调用onResolved
function(err) {return err }, //如果操作失败,调用onRejected
).then(
res => {}) // 上一个then的返回值
// promise2 = Promise{}
大概思路
调用then时(如:xxx.then( ()=>1,()=>2 )),新增MyPromise类作为当前then操作的对象,将fn1/fn2作为成功/失败的回调;
开始收集依赖,用于数据传递
根据当前MyPromise实例的status,判断成功/失败,并将值传递给下一个;本质上就是更新最新的MyPromise类的属性值
this.thenQueue.forEach(([nextPromise, onResolved,]) => { if (onResolved) { // 将当前实例的值,作为then的resolve回调的参数,这样then内部就能够获取到 const valueOrPromise = onResolved(this._value); // 将传入的值更新到最新的MyPromise类内部,以便传递给下一个then if (isThenable(valueOrPromise)) { // Promise处理 valueOrPromise.then( value => nextPromise._onResolved(value), reason => nextPromise._onResolved(reason) ) } else { // 非Promise nextPromise._onResolved(valueOrPromise) } } else { nextPromise._onResolved(this._value) } })
JS代码
_onResolved(value) {
const {_state,} = this
const {PENDING, RESOLVED} = STATUS
if (_state === PENDING) {
this._value = value
this._state = RESOLVED
this._handleResolvedQueue() // 对Resolved的处理
}
}
_onRejected(reason) {
const {_state,} = this
const {PENDING, REJECTED} = STATUS
if (_state === PENDING) {
this._reason = reason
this._state = REJECTED
this._handleRejectedQueue() // 对Rejected的处理
}
}
then(onResolved, onRejected) {
const {_state, _thenQueue} = this
const {RESOLVED, REJECTED} = STATUS
const nextPromise = new MyPromise()
// 对nextPromise, onResolved, onRejected进行收集;
this._thenQueue.push([nextPromise, onResolved, onRejected]);
if (_state === RESOLVED) {
this._handleResolvedQueue()
} else if (_state === REJECTED) {
this._handleRejectedQueue()
}
return nextPromise
}
// 对Resolved的处理
_handleResolvedQueue() {
const {_value,} = this
// 收集好的onResolved
this._thenQueue.forEach(([nextPromise, onResolved,]) => {
if (onResolved) {
// 对上一次的then中 return new MyPromise(...) / return value ?
// TODO: onResolved 是可能会出错的 handle err
const valueOrPromise = onResolved(_value)
if (isThenable(valueOrPromise)) { // Promise处理
valueOrPromise.then(
value => nextPromise._onResolved(value),
reason => nextPromise._onResolved(reason)
)
} else { // 非Promise,将值传递给下一个
nextPromise._onResolved(valueOrPromise)
}
} else { // 如果.then中没有传入resolve方法,则只是对上一个Promise的resolved的值中转,传给下一个
nextPromise._onResolved(_value)
}
}
)
// 重置_thenQueue
this._thenQueue = []
}
// 对Rejected的处理
_handleRejectedQueue() {
const {_reason} = this
// 收集好的onRejected
this._thenQueue.forEach(([nextPromise, _, onResolved,]) => {
if (onResolved) {
// 对上一次的then中 return new MyPromise(...) / return value ?
// TODO: onResolved 是可能会出错的 handle err
const valueOrPromise = onResolved(_reason)
if (isThenable(valueOrPromise)) { // Promise处理
valueOrPromise.then(
value => nextPromise._onRejected(value),
reason => nextPromise._onRejected(reason)
)
} else { // 非Promise,此时需要将值以Resolved的状态传递给下一个
nextPromise._onResolved(valueOrPromise)
}
} else { // 如果.then中没有传入resolve方法,则只是对上一个Promise的resolved的值中转,传给下一个
nextPromise._onRejected(_reason)
}
}
)
// 重置_thenQueue
this._thenQueue = []
}
案例
const p0 = new MyPromise((resolve, reject) => {
// resolve(1)
reject(2)
})
console.log("开始")
p0.then(
res => {
console.log("res==>", res)
return 200
},
err => {
console.log("err==>", err)
return 404
})
.then(res => {
console.log("nextThen==>", res)
})
console.log("结束")
// 开始
// 结束
// res==> 1 or err==> 2
// nextThen==> 200 or nextThen==> 404
正确的输出顺序应该是 res和nextThen 应该再开始-结束中间,由于我们做了简单的异步处理,优化也很简单,把异步操作放到_handleResolvedQueue和_handleResolvedQueue即可。
catch的实现
本质上是基于then方法的实现
catch(Rejected) {
return this.then(undefined, Rejected)
}
finally实现
与then的原理类似
finally(sideEffect) {
const {_state, _value} = this
const {PENDING, RESOLVED} = STATUS
if (_state !== PENDING) {
if (sideEffect) {
// TODO: 副作用函数是有可能出错的 handle error
sideEffect()
}
return _state === RESOLVED ? MyPromise.resolve(_value) : MyPromise.reject(_value)
} else {
const nextPromise = new MyPromise()
this._finallyQueue.push([nextPromise, sideEffect]);
return nextPromise
}
}
完整代码
const STATUS = {
PENDING: 'pending',
RESOLVED: 'resolved',
REJECTED: 'rejected',
}
// 是否MyPromise类型
const isThenable = (val) => val && (typeof val.then === 'function');
class MyPromise {
constructor(executor) {
// 被resolved的值
this._value = undefined;
// 被rejected的值
this._reason = undefined;
this._state = STATUS.PENDING;
// 收集对应返回的Promise以及处理函数
this._thenQueue = [];
// 收集副作用函数
this._finallyQueue = [];
// TODO: executor是用户传入的函数,考虑到执行executor的过程中有可能出错,所以可以考虑try/catch块给包起来
if (executor) {
// 执行executor时,为保证resolve,reject内部this!=undefined
executor(this._onResolved.bind(this), this._onRejected.bind(this))
}
}
_onResolved(value) {
const {_state,} = this
const {PENDING, RESOLVED} = STATUS
if (_state === PENDING) { // 确保_state只会修改一次
this._value = value
this._state = RESOLVED
this._handleResolvedQueue()
}
}
_onRejected(reason) {
const {_state,} = this
const {PENDING, REJECTED} = STATUS
if (_state === PENDING) { // 确保_state只会修改一次
this._reason = reason
this._state = REJECTED
this._handleRejectedQueue()
}
}
then(onResolved, onRejected) {
const {_state, _thenQueue} = this
const {RESOLVED, REJECTED} = STATUS
const nextPromise = new MyPromise()
// 对nextPromise, onResolved, onRejected进行收集;
this._thenQueue.push([nextPromise, onResolved, onRejected]);
if (_state === RESOLVED) {
this._handleResolvedQueue()
} else if (_state === REJECTED) {
this._handleRejectedQueue()
}
return nextPromise
}
// 对Resolved的处理
_handleResolvedQueue() {
// TODO: 简单的异步处理 可优化
setTimeout(() => {
const {_value,} = this
// 收集好的onResolved
this._thenQueue.forEach(([nextPromise, onResolved,]) => {
if (onResolved) {
// 对上一次的then中 return new MyPromise(...) / return value ?
// TODO: onResolved 是可能会出错的 handle err
const valueOrPromise = onResolved(_value)
if (isThenable(valueOrPromise)) { // Promise处理
valueOrPromise.then(
value => nextPromise._onResolved(value),
reason => nextPromise._onResolved(reason)
)
} else { // 非Promise,将值传递给下一个
nextPromise._onResolved(valueOrPromise)
}
} else { // 如果.then中没有传入resolve方法,则只是对上一个Promise的resolved的值中转,传给下一个
nextPromise._onResolved(_value)
}
}
)
this._finallyQueue.forEach(([nextPromise, sideEffect]) => {
if (sideEffect) {
// TODO: 副作用函数是有可能出错的 handle error
sideEffect()
}
nextPromise._onResolved(_value)
})
// 重置_thenQueue
this._thenQueue = []
this._finallyQueue = []
})
}
// 对Rejected的处理
_handleRejectedQueue() {
// TODO: 简单的异步处理 可优化
setTimeout(() => {
const {_reason} = this
// 收集好的onRejected
this._thenQueue.forEach(([nextPromise, _, onResolved,]) => {
if (onResolved) {
// 对上一次的then中 return new MyPromise(...) / return value ?
// TODO: onResolved 是可能会出错的 handle err
const valueOrPromise = onResolved(_reason)
if (isThenable(valueOrPromise)) { // Promise处理
valueOrPromise.then(
value => nextPromise._onRejected(value),
reason => nextPromise._onRejected(reason)
)
} else { // 非Promise,此时需要将值以Resolved的状态传递给下一个
nextPromise._onResolved(valueOrPromise)
}
} else { // 如果.then中没有传入resolve方法,则只是对上一个Promise的resolved的值中转,传给下一个
nextPromise._onRejected(_reason)
}
}
)
this._finallyQueue.forEach(([nextPromise, sideEffect]) => {
if (sideEffect) {
// TODO: 副作用函数是有可能出错的 handle error
sideEffect()
}
nextPromise._onRejected(_reason)
})
// 重置_thenQueue
this._thenQueue = []
this._finallyQueue = []
})
}
catch(Rejected) {
return this.then(undefined, Rejected)
}
finally(sideEffect) {
const {_state, _value} = this
const {PENDING, RESOLVED} = STATUS
if (_state !== PENDING) {
if (sideEffect) {
// TODO: 副作用函数是有可能出错的 handle error
sideEffect()
}
return _state === RESOLVED ? MyPromise.resolve(_value) : MyPromise.reject(_value)
} else {
const nextPromise = new MyPromise()
this._finallyQueue.push([nextPromise, sideEffect]);
return nextPromise
}
}
}
MyPromise.resolve = (value) => {
return new MyPromise((resolve, reject) => {
resolve(value)
})
}
MyPromise.reject = (value) => {
return new MyPromise((resolve, reject) => {
reject(value)
})
}
总结
- 核心是then方法的实现,其他方法是对promise的扩充。
- 本文只是简单实现一个初步的 promise,而真正的 promise 比它复杂很多,涉及到各种异常情况、边界情况的处理。
最后一句
学习心得!若有不正,还望斧正。希望掘友们不要吝啬对我的建议。