一. 手写一下promise
思路
核心点
因为每天都在使用promise,所以从promise的使用形式来思考该怎么封装promise
形式上:
- 入参为一个立即执行的函数,且函数有两个方法resolve和reject可以调用
- 调用resolve会执行then里面的方法,调用reject会执行catch(或者是then里面的第二个参数的方法)
- 因为是链式操作,做所以then、catch等方法要么返回this,要么返回对应的promise来完成链式操作,如果是this,会同时调用then和catch,所以这个地方选择返回promise来完成链式操作
使用上:
- 有三种状态,分别是pendding、fulfilled、rejected
- 异步操作,所以需要有tasklist的数组来完成
由这些点出发,来一一实现,开始coding
代码
1. 完成立即执行,同步调用
const STATUS = {
PENDDING: 'pendding',
FULFILLED: 'fulfilled',
REJECTED: 'rejected'
}
class myPromise {
constructor(rightnow) {
this.status = STATUS.PENDDING
this.value = undefined
this.reason = undefined
const resolve = value => {
if (this.status = STATUS.PENDDING) {
this.status = STATUS.FULFILLED
this.value = value
}
}
const reject = reason => {
if (this.status = STATUS.PENDDING) {
this.status = STATUS.REJECTED
this.reason = reason
}
}
try {
rightnow(resolve, reject)
} catch (error) {
throw error
}
}
then(onResolved, onRejected) {
const actions = {
[STATUS.FULFILLED]: () => {
onResolved(this.value)
},
[STATUS.REJECTED]: () => {
onRejected(this.reason)
}
}
actions[this.status]?.()
return this
}
catch(onRejected) {
onRejected(this.reason)
return this
}
}
2. 实现异步调用
const STATUS = {
PENDDING: 'pendding',
FULFILLED: 'fulfilled',
REJECTED: 'rejected'
}
class myPromise {
constructor(rightnow) {
this.status = STATUS.PENDDING
this.value = undefined
this.reason = undefined
this.onRejectedCBs = []
this.onResolvedCBs = []
const resolve = value => {
if (this.status = STATUS.PENDDING) {
this.status = STATUS.FULFILLED
this.value = value
this.onResolvedCBs.forEach(fn => fn())
}
}
const reject = reason => {
if (this.status = STATUS.PENDDING) {
this.status = STATUS.REJECTED
this.reason = reason
this.onRejectedCBs.forEach(fn => fn())
}
}
try {
rightnow(resolve, reject)
} catch (error) {
throw error
}
}
then(onResolved, onRejected) {
const actions = {
[STATUS.FULFILLED]: () => {
onResolved(this.value)
},
[STATUS.REJECTED]: () => {
onRejected(this.reason)
},
[STATUS.PENDDING]: () => {
this.onRejectedCBs.push(() => {
onRejected(this.reason)
})
this.onResolvedCBs.push(() => {
onResolved(this.value)
})
}
}
actions[this.status]?.()
return this
}
catch(onRejected) {
return this
}
}
3. 实现链式操作
const STATUS = {
PENDDING: 'pendding',
FULFILLED: 'fulfilled',
REJECTED: 'rejected'
}
class myPromise {
constructor(rightnow) {
this.status = STATUS.PENDDING
this.value = undefined
this.reason = undefined
this.onRejectedCBs = []
this.onResolvedCBs = []
const resolve = value => {
if (this.status = STATUS.PENDDING) {
this.status = STATUS.FULFILLED
this.value = value
this.onResolvedCBs.forEach(fn => fn())
}
}
const reject = reason => {
if (this.status = STATUS.PENDDING) {
this.status = STATUS.REJECTED
this.reason = reason
this.onRejectedCBs.forEach(fn => fn())
}
}
try {
rightnow(resolve, reject)
} catch (error) {
throw error
}
}
then(onResolved, onRejected) {
const re_promise = new myPromise((resolve, reject) => {
const actions = {
[STATUS.FULFILLED]: () => {
const x = onResolved(this.value)
/**
* resolvePromise需要满足如下含义
* 1. 如果x为re_promise本身直接跳reject,否则无限循环
* 2. 如果x不为promise,直接将x的值resolve到下一个then中去
* 3. 如果x位reject,直接返回reject到下一个catch中去
*/
resolvePromise(re_promise, x, resolve, reject)
},
[STATUS.REJECTED]: () => {
const x = onRejected(this.reason)
resolvePromise(re_promise, x, resolve, reject)
},
[STATUS.PENDDING]: () => {
this.onRejectedCBs.push(() => {
const x = onRejected(this.reason)
resolvePromise(re_promise, x, resolve, reject)
})
this.onResolvedCBs.push(() => {
const x = onResolved(this.value)
resolvePromise(re_promise, x, resolve, reject)
})
}
}
actions[this.status]?.()
})
return re_promise
}
catch(onRejected) {
this.then(null, onRejected)
}
}
/**
*
* @param {Promise} promise 返回的promise
* @param {any} x 前一个then的return值
* @param {function} resolve promise的resolve
* @param {function} reject promise的reject
* @returns Promise
*/
const resolvePromise = (promise, x, resolve, reject) => {
if (promise === x) {
return reject(new Error('then中的方法返回的promise和构造函数一样,会无限循环'))
}
let caller = false
if (isPromiseLike(x)) {
try {
const then = x.then
then.call(x, (y) => {
if (caller) return
caller = true
resolvePromise(promise, y, resolve, reject)
}, err => {
if (caller) return
caller = true
reject(err)
})
} catch (error) {
if (caller) return
caller = true
reject(error)
}
} else {
resolve(x)
}
}
// note: Promise A+ 规范: https://promisesaplus.com/
const isPromiseLike = p => p !== null && (typeof p === 'object' || typeof p === 'function') && typeof p.then === 'function'
new myPromise((resolve, reject) => {
setTimeout(() => {
resolve('resolve')
}, 1000)
setTimeout(() => {
reject('reject')
}, 3000)
}).then((res => {
console.log('res------>', res)
}), (err) => {
console.log('err------>', err)
})
二. 实现Promise.all方法
思路
核心点
- promise.all的调用入参是一个数组(准确来讲是迭代器)
- 如果所有的promise都返回成功,则执行then,有一个失败则执行catch
根据这两点,写代码
代码
if(!Promise.all) {
Promise.prototype.all = function(promises) {
return new Promise((resolve, reject) => {
let result = []
let count = 0
let fulfillCount
// note: 因为是迭代器,所以这个地方用forof更加严谨一些
for (const item of promises) {
const index = count
count++
Promise.resolve(item).then(res => {
result[index] = res
fulfillCount++
// 因为Promise是微任务,同步的for执行完毕之后才会执行Promise
if(fulfillCount === count) {
resolve(result)
}
}, reject)
}
})
}
}
三. isPromiseLike(p)(判断p是否是一个类Promise)
这个问题主要考察的是你是否了解Promise A+规范:promisesaplus.com/
这个问题出的挺好的,代码并不难,但是考点很明确
所以代码就很简单了
const isPromiseLike = p => p !== null && (typeof p === 'object' || typeof p === 'function') && typeof p.then === 'function'