Promise
- state
- then
state有三种,pending fulfilled rejected
then有两个回调参数,onFulfilled onRejected
Promise状态的扭转时会从 pending 变为其他两种状态,此时会调用 then 传入的两个回调分别处理这两种状态
同一个promise可以调用多个then,状态扭转时,按照then调用的顺序执行他们传入的回调。
当then接受的两个参数不是函数时,then会给出一个默认函数用来透传参数
promise 初始化时传入的回调时立即执行的,而 then 的两个回调是通过 queueMicrotask 放入微任务队列执行的
resolvePromise 做的特殊处理:
- 如果 promise2 和 x 相等,那么 reject TypeError
- 如果 x 是一个 promsie
如果x是pending态,那么promise必须要在pending,直到 x 变成 fulfilled or rejected.
如果 x 被 fulfilled, fulfill promise with the same value.
如果 x 被 rejected, reject promise with the same reason. - 如果 x 是一个 object 或者 是一个 function
let then = x.then.
如果 x.then 这步出错,那么 reject promise with e as the reason.
如果 then 是一个函数,then.call(x, resolvePromiseFn, rejectPromise)
resolvePromiseFn 的 入参是 y, 执行 resolvePromise(promise2, y, resolve, reject);
rejectPromise 的 入参是 r, reject promise with r.
如果 resolvePromise 和 rejectPromise 都调用了,那么第一个调用优先,后面的调用忽略。
如果调用then抛出异常e
如果 resolvePromise 或 rejectPromise 已经被调用,那么忽略
则,reject promise with e as the reason
如果 then 不是一个function. fulfill promise with x.
自己代码实现
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
function isFunction (f) {
return typeof f === 'function'
}
class MPromise {
ONFULFILLED_CALLBACKS = []
ONREJECTED_CALLBACKS = []
_status = PENDING
constructor(fn) {
this.status = PENDING
this.value = null
this.reason = null
// 立即执行fn
try {
fn(this.resolve.bind(this), this.reject.bind(this))
} catch(e) {
this.reject(e)
}
}
get status() {
return this._status
}
set status(s) {
this._status = s
switch(s) {
case FULFILLED: {
this.ONFULFILLED_CALLBACKS.forEach(item => {
item(this.value)
})
break
}
case REJECTED: {
this.ONREJECTED_CALLBACKS.forEach(item => {
item(this.reason)
})
break
}
}
}
resolve(value) {
if (this.status === PENDING) {
this.value = value
this.status = FULFILLED
}
}
reject(reason) {
if (this.status === PENDING) {
this.reason = reason
this.status = REJECTED
}
}
then(onFulfilled, onRejected) {
const realOnFulfilled = isFunction(onFulfilled) ? onFulfilled : v => v
const realOnRejected = isFunction(onRejected) ? onRejected : reason => {
throw reason
}
const promise2 = new MPromise((resolve, reject) => {
const onFulFillMicroTask = (value) => {
queueMicrotask(() => {
try {
const x = realOnFulfilled(value)
this.resolvePromsie(promise2, x, resolve, reject)
} catch(e) {
reject(e)
}
})
}
const onRejectMicroTask = (reason) => {
queueMicrotask(() => {
try {
const x = realOnRejected(reason)
this.resolvePromsie(promise2, x, resolve, reject)
} catch(e) {
reject(e)
}
})
}
// 如果then在调用的时候promise的状态已经发生了变化,需要手动调用回调
switch(this.status) {
case FULFILLED: {
onFulFillMicroTask(this.value)
break
}
case REJECTED: {
onRejectMicroTask(this.reason)
break
}
case PENDING: {
this.ONFULFILLED_CALLBACKS.push(onFulFillMicroTask)
this.ONREJECTED_CALLBACKS.push(onRejectMicroTask)
}
}
})
return promise2
}
catch(onRejected) {
return this.then(null, onRejected)
}
resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError('The promise and the return value are the same'))
} else if (x instanceof MPromise) {
// 这里我并没有用queueMicrotask
x.then(value => {
this.resolvePromise(promise2, value, resolve, reject)
}, reject)
} else if (typeof x === 'object' || isFunction(x)) {
if (x === null) return resolve(x)
let then = null
try {
then = x.then
} catch(e) {
return reject(e)
}
if (isFunction(then)) {
// 保证对该 promise like 对象的then函数只接受其一次状态扭转调用,
// 因为该 promise like 对象不可信,所以此处需要严格限制。
// 上面判断x instance MPromise保证x整个对象是我们自己控制的,所以无需判断
let called = false
try {
then.call(
x,
(value) => {
if (called) return
called = true
this.resolvePromise(promise2, value, resolve, reject)
},
(reason) => {
if (called) return
called = true
reject(reason)
}
)
} catch(e) {
if (called) return
// 只有在调用onFulfill onReject扭转状态时才需要called置为true,普通抛错并不代表状态完成扭转,所以还可以调用扭转回调
return reject(e)
}
} else {
resolve(x)
}
} else {
resolve(x)
}
}
static resolve(value) {
if (value instanceof MPromise) return value
return new MPromise((resolve) => {
resolve(value)
})
}
static reject(reason) {
return new MPromise((resolve, reject) => {
reject(reason)
})
}
static race(promiseList) {
return new MPromise((resolve, reject) => {
if (!promiseList || !promiseList.length) return resolve()
promiseList.forEach(promise => {
MPromise.resolve(promise).then(
(value) => {
resolve(value)
},
reason => {
reject(reason)
}
)
})
})
}
}
const promise = new MPromise((resolve, reject) => {
resolve(123)
})
const promise2 = promise.then((value) => {
}, (reason) => {
})
// const test = new MPromise((resolve, reject) => {
// setTimeout(() => {
// reject(111);
// }, 1000);
// }).then((value) => {
// console.log('then');
// }).catch((reason) => {
// console.log('catch');
// })
MPromise.race([
// 1,
// MPromise.resolve(2),
new MPromise((resolve, reject) => {
setTimeout(() => {
resolve(3)
}, 1000);
}),
new MPromise((resolve, reject) => {
setTimeout(() => {
reject(4)
}, 1100);
}),
]).then(
(value) => {
console.log('resolve', value)
},
(reason) => {
console.log('reject', reason)
}
)
// 对于代码中有的实现, 有的同学可能会有疑问, 这里为什么会有异常, 为什么一定要这么写.
// 大家可以去看一下promise aplus的测试用例, 里面列举了各种奇奇怪怪的异常情况 https://github.com/promises-aplus/promises-tests/blob/master/lib/tests.