Promise
- state
- then
state有三種,pending fulfilled rejected
then有兩個(gè)回調(diào)參數(shù)绢掰,onFulfilled onRejected
Promise狀態(tài)的扭轉(zhuǎn)時(shí)會(huì)從 pending 變?yōu)槠渌麅煞N狀態(tài)锄贷,此時(shí)會(huì)調(diào)用 then 傳入的兩個(gè)回調(diào)分別處理這兩種狀態(tài)
同一個(gè)promise可以調(diào)用多個(gè)then,狀態(tài)扭轉(zhuǎn)時(shí)曼月,按照then調(diào)用的順序執(zhí)行他們傳入的回調(diào)谊却。
當(dāng)then接受的兩個(gè)參數(shù)不是函數(shù)時(shí),then會(huì)給出一個(gè)默認(rèn)函數(shù)用來(lái)透?jìng)鲄?shù)
promise 初始化時(shí)傳入的回調(diào)時(shí)立即執(zhí)行的哑芹,而 then 的兩個(gè)回調(diào)是通過(guò) queueMicrotask 放入微任務(wù)隊(duì)列執(zhí)行的
resolvePromise 做的特殊處理:
- 如果 promise2 和 x 相等炎辨,那么 reject TypeError
- 如果 x 是一個(gè) promsie
如果x是pending態(tài),那么promise必須要在pending,直到 x 變成 fulfilled or rejected.
如果 x 被 fulfilled, fulfill promise with the same value.
如果 x 被 rejected, reject promise with the same reason. - 如果 x 是一個(gè) object 或者 是一個(gè) function
let then = x.then.
如果 x.then 這步出錯(cuò)聪姿,那么 reject promise with e as the reason.
如果 then 是一個(gè)函數(shù)碴萧,then.call(x, resolvePromiseFn, rejectPromise)
resolvePromiseFn 的 入?yún)⑹?y, 執(zhí)行 resolvePromise(promise2, y, resolve, reject);
rejectPromise 的 入?yún)⑹?r, reject promise with r.
如果 resolvePromise 和 rejectPromise 都調(diào)用了乙嘀,那么第一個(gè)調(diào)用優(yōu)先,后面的調(diào)用忽略破喻。
如果調(diào)用then拋出異常e
如果 resolvePromise 或 rejectPromise 已經(jīng)被調(diào)用虎谢,那么忽略
則,reject promise with e as the reason
如果 then 不是一個(gè)function. fulfill promise with x.
自己代碼實(shí)現(xiàn)
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
// 立即執(zhí)行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在調(diào)用的時(shí)候promise的狀態(tài)已經(jīng)發(fā)生了變化曹质,需要手動(dòng)調(diào)用回調(diào)
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) {
// 這里我并沒(méi)有用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)) {
// 保證對(duì)該 promise like 對(duì)象的then函數(shù)只接受其一次狀態(tài)扭轉(zhuǎn)調(diào)用婴噩,
// 因?yàn)樵?promise like 對(duì)象不可信,所以此處需要嚴(yán)格限制羽德。
// 上面判斷x instance MPromise保證x整個(gè)對(duì)象是我們自己控制的几莽,所以無(wú)需判斷
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
// 只有在調(diào)用onFulfill onReject扭轉(zhuǎn)狀態(tài)時(shí)才需要called置為true,普通拋錯(cuò)并不代表狀態(tài)完成扭轉(zhuǎn)宅静,所以還可以調(diào)用扭轉(zhuǎn)回調(diào)
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)
}
)
// 對(duì)于代碼中有的實(shí)現(xiàn), 有的同學(xué)可能會(huì)有疑問(wèn), 這里為什么會(huì)有異常, 為什么一定要這么寫.
// 大家可以去看一下promise aplus的測(cè)試用例, 里面列舉了各種奇奇怪怪的異常情況 https://github.com/promises-aplus/promises-tests/blob/master/lib/tests.