看过很多版本的自定义promise,感觉都不够详细完整,特此整理一份完整版,附完整代码注释 每个实现代码块都可单独运行,并附上测试代码,可自行测试
一、Promise的核心用法
- 实例方法:
then,catch,finally - 静态方法:
resolve,reject,race,all,allSettled,any,withResolvers
// 实例化 并管理异步任务
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
// reject('error')
}, 1000);
})
// then方法获取成功/失败结果
// 参数1:成功时执行的回调函数
// 参数2:失败时执行的回调函数
p.then(res => {
console.log('res:', res)
return 'success2'
}, err => {
console.log('err:', err)
}).then(res2 => {
console.log('res2:', res2)
})
二、自定义Promise核心功能
(一)构造函数
需求
- 实现
MYPromise类,进行实例化 - 实例化时传入回调函数
- 回调函数立刻执行
- 回调函数接收函数
resolve和reject
实现步骤
- 定义类
HMPromise - 添加构造函数
constructor,构造函数需要接收回调函数func - 定义resolve/reject
- 执行回调函数
// 1. 定义类
class MYPromise {
// 2. 添加构造函数,构造函数需要接收回调函数func
constructor(func) {
// 3. 定义resolve/reject
const resolve = (result) => {
console.log('resolve-执行啦:', result)
}
const reject = (result) => {
console.log('reject-执行啦:', result)
}
// 4. 执行回调函数
func(resolve, reject)
}
}
// ------实例化测试------
const p = new MYPromise((resolve, reject) => {
console.log('执行啦');
resolve('success')
reject('error')
})
// ------打印------
// 执行啦
// resolve-执行 success
// reject-执行 error
(二)state状态、成功和失败原因
需求
MYPromise增加state属性,只能是如下3个值pending:待定,默认状态fulfilled:已兑现,操作成功rejected:已拒绝,操作失败
MYPromise增加result属性,记录成功/失败原因- 调用
resolve时传入具体原因,如果状态为pending则更改状态为fulfilled并记录兑现原因 - 调用
reject时传入具体原因,如果状态为pending则更改状态为rejected并记录拒绝原因 - 注意:状态不可逆
实现步骤
- 定义常量保存状态
MYPromise中定义- 属性:
state保存状态,result成功/失败原因 - 修改
state的私有方法,修改状态并记录result - 注意:
state只有在pending时,才可以修改,且不可逆
- 属性:
// 定义全局常量,方便使用
const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"
class MYPromise {
// 1. 添加状态,初始化状态为pending
state = PENDING
// 2. 添加原因
result = undefined
constructor(func) {
// 3. 调整resolve/reject
// 5. 状态不可逆
// 改状态: pending->fulfilled
// 记录原因
const resolve = (result) => {
if (this.state === PENDING) {
this.state = FULFILLED
this.result = result
}
}
// 4.改状态: pending->rejected
// 记录原因
const reject = (result) => {
if (this.state === PENDING) {
this.state = REJECTED
this.result = result
}
}
func(resolve, reject)
}
}
// ------实例化测试------
const p = new MYPromise((resolve, reject) => {
resolve('success') // pending -> fulfilled
reject('error') // pending -> rejected
})
// p.state 添加内部属性作为状态
// p.result 添加内部属性作为原因
(三)then方法-成功和失败回调
需求
- then方法的回调函数1: 状态变为
fulfilled时触发,并获取成功结果 - then方法的回调函数2:状态变为
rejected时触发,并获取失败原因 - then方法的回调函数1或2没有传递的特殊情况处理,参考:then方法的参数
实现步骤
- 增加
then方法,根据不同的状态执行对应的回调函数,并传入result- 参数1:成功的回调函数,onFulfilled
- 参数2:失败的回调函数,onRejected
- 判断参数
- 判断传入的onFulfilled和onRejected是否为函数
- 设置默认值(参考文档)
- 根据状态调用onFulfilled或onRejected并传入兑现或拒绝原因
const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"
class MYPromise {
state = PENDING
result = undefined
constructor(func) {
const resolve = (result) => {
if (this.state === PENDING) {
this.state = FULFILLED
this.result = result
}
}
const reject = (result) => {
if (this.state === PENDING) {
this.state = REJECTED
this.result = result
}
}
func(resolve, reject)
}
// 1. 添加then()实例方法
then(onFulfilled, onRejected) {
// 2. 参数判断(参考文档)
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
if (this.state === FULFILLED) {
// 3.执行成功回调,并传入原因
onFulfilled(this.result)
} else if (this.state === REJECTED) {
// 3.执行失败回调,并传入原因
onRejected(this.result)
}
}
}
// ------实例化测试------
const p = new MYPromise((resolve, reject) => {
resolve('success') // pending -> fulfilled
// reject('error') // pending -> rejected
})
p.then(res => {
console.log("成功回调", res);
}, err => {
console.log("失败回调", err);
})
// 此时只传了一个参数,onRejected 会抛出错误
p.then( err => {
console.log("失败回调", err); // Uncaught error
})
(四)then方法-异步和多次调用
需求
- 实例化传入的回调函数,内部支持异步操作
then方法支持多次调用
实现步骤
- 定义属性:保存传入的回调函数:
[] MYPromise添加私有属性#handlers- 保存then方法调用时状态为
pending的回调函数 - 格式为对象数组:
[{onFulfilled,onRejected}...]
- 保存then方法调用时状态为
- 调用成功回调:
resolve内部,取出数组#handlers中的所有onFulfilled回调函数进行调用 - 调用失败回调:
reject内部,取出数组#handlers中的所有onRejected回调函数进行调用
const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"
class MYPromise {
state = PENDING
result = undefined
// 1. 定义实例属性,私有属性,只能在类的内部调用,保存传入的回调函数:[]
#handlers = [] // [{onFulfilled,onRejected}...]
constructor(func) {
const resolve = (result) => {
if (this.state === PENDING) {
this.state = FULFILLED
this.result = result
// 3. 调用成功回调
this.#handlers.forEach(({ onFulfilled }) => {
onFulfilled(this.result)
})
}
}
const reject = (result) => {
if (this.state === PENDING) {
this.state = REJECTED
this.result = result
// 4. 调用失败回调
this.#handlers.forEach(({ onRejected }) => {
onRejected(this.result)
})
}
}
func(resolve, reject)
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
if (this.state === FULFILLED) {
onFulfilled(this.result)
} else if (this.state === REJECTED) {
onRejected(this.result)
} else if (this.state === PENDING) {
// 此时状态没有改变说明没有调用,为异步状态
// 2. 保存回调函数
this.#handlers.push({
onFulfilled, onRejected
})
}
}
}
// ------实例化测试------
const p = new MYPromise((resolve, reject) => {
setTimeout(() => {
// resolve('success')
reject('error')
}, 2000)
})
p.then(res => {
console.log("then1", res);
}, err => {
console.log("then1", err); // then1 error
})
p.then(res => {
console.log("then2", res);
}, err => {
console.log("then2", err);// then2 error
})
(五)then方法-异步任务
需求
- 如下代码打印结果为
1,3,2,期望结果应为1,2,3 - 核心:让then方法的回调函数以异步任务的方式执行
console.log('1')
const p = new MYPromise((resolve, reject) => {
resolve('3')
})
p.then(res => {
console.log(res)
})
console.log('2')
参考资料
以上都可以实现异步任务
queueMicrotask:新式浏览器均支持,node11开始支持,ie不支持MutationObserver:新式浏览器均支持,ie11开始支持setImmediate:新式浏览器只有edge支持。ie10开始支持setTimeout:浏览器支持,node支持
实现步骤
- 封装执行异步任务的函数
- 定义函数传入异步任务(回调函数)
- 内部根据实际情况判断并使用开启异步任务的api即可,比如
queueMicrotask,MutationObserver - 调用的
api可以根据实际情况进行调整 - 如果都无法执行,使用
setTimeout兜底 - 调整
then中的逻辑,fulFilled,rejected,pending3种状态时的回调函数,使用封装的函数包装一次
// 1. 定义函数
function runAsynctask(callback) {
// 2. 调用核心api(queueMicrotask,MutationObserver,setTimeout)
if (typeof queueMicrotask === 'function') {
queueMicrotask(callback)
} else if (typeof MutationObserver === 'function') {
const obs = new MutationObserver(callback)
const divNode = document.createElement('div')
obs.observe(divNode, { childList: true })
divNode.innerText = '监测元素改变,才会执行'
} else {
setTimeout(callback, 0)
}
}
const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"
class MYPromise {
state = PENDING
result = undefined
#handlers = []
constructor(func) {
const resolve = (result) => {
if (this.state === PENDING) {
this.state = FULFILLED
this.result = result
this.#handlers.forEach(({ onFulfilled }) => {
onFulfilled(this.result)
})
}
}
const reject = (result) => {
if (this.state === PENDING) {
this.state = REJECTED
this.result = result
this.#handlers.forEach(({ onRejected }) => {
onRejected(this.result)
})
}
}
func(resolve, reject)
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
// 3. 使用封装函数调用
if (this.state === FULFILLED) {
runAsynctask(() => {
onFulfilled(this.result)
})
} else if (this.state === REJECTED) {
runAsynctask(() => {
onRejected(this.result)
})
} else if (this.state === PENDING) {
this.#handlers.push({
onFulfilled: () => {
runAsynctask(() => {
onFulfilled(this.result)
})
}, onRejected: () => {
runAsynctask(() => {
onRejected(this.result)
})
}
})
}
}
}
// ------实例化测试------
console.log('1')
const p = new MYPromise((resolve, reject) => {
resolve('3')
})
p.then(res => {
console.log(res)
})
console.log('2')
// -----打印结果-------
// 1
// 2
// 3
(六)链式编程-fulfilled状态-返回值+异常
需求
then的链式编程- 目前只考虑
then的第一个回调函数- 返回普通值
- 内部出现异常
const p = new MYPromise((resolve, reject) => {
resolve(1)
})
p.then(res => {
console.log(res)
// throw 'throw-error'
return 2
}).then(res => {
console.log(res) // 2
}, err => {
console.log(err)
})
实现步骤
- 调整
then方法,返回一个新的MYPromise对象 - 使用
try-catch捕获异常,并通过reject传递 - 内部获取
onFulfilled的执行结果,并通过resolve传递
// 封装的异步函数
function runAsynctask(callback) {
if (typeof queueMicrotask === 'function') {
queueMicrotask(callback)
} else if (typeof MutationObserver === 'function') {
const obs = new MutationObserver(callback)
const divNode = document.createElement('div')
obs.observe(divNode, { childList: true })
divNode.innerText = '监测元素改变,才会执行'
} else {
setTimeout(callback, 0)
}
}
const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"
class MYPromise {
state = PENDING
result = undefined
#handlers = []
constructor(func) {
const resolve = (result) => {
if (this.state === PENDING) {
this.state = FULFILLED
this.result = result
this.#handlers.forEach(({ onFulfilled }) => {
onFulfilled(this.result)
})
}
}
const reject = (result) => {
if (this.state === PENDING) {
this.state = REJECTED
this.result = result
this.#handlers.forEach(({ onRejected }) => {
onRejected(this.result)
})
}
}
func(resolve, reject)
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
// 1. 链式调用,必须返回新Promise实例
const p2 = new MYPromise((resolve, reject) => {
if (this.state === FULFILLED) {
runAsynctask(() => {
// 2. 获取返回值
try {
const x = onFulfilled(this.result)
// 2.1 处理返回值,通过resolve传递
resolve(x)
} catch (error) {
// 2.2 处理异常,通过reject传递
reject(error)
}
})
} else if (this.state === REJECTED) {
runAsynctask(() => {
onRejected(this.result)
})
} else if (this.state === PENDING) {
this.#handlers.push({
onFulfilled: () => {
runAsynctask(() => {
onFulfilled(this.result)
})
}, onRejected: () => {
runAsynctask(() => {
onRejected(this.result)
})
}
})
}
})
return p2
}
}
(七)链式编程-fulfilled状态-返回Promise的情况
需求:
then的链式编程- 目前只考虑
then的第一个回调函数- 返回
Promise
- 返回
const p = new MYPromise((resolve, reject) => {
resolve(1)
})
p.then(res => {
return new MYPromise((resolve, reject) => {
resolve(2)
// reject('error')
})
}).then(res => {
console.log('p2:', res) // 2
}, err => {
console.log('p2:', err) // error
})
实现步骤
- 判断是否为
MYPromise实例 - 调用
then方法依次传入回调函数
// 封装的异步函数
function runAsynctask(callback) {
if (typeof queueMicrotask === 'function') {
queueMicrotask(callback)
} else if (typeof MutationObserver === 'function') {
const obs = new MutationObserver(callback)
const divNode = document.createElement('div')
obs.observe(divNode, { childList: true })
divNode.innerText = '监测元素改变,才会执行'
} else {
setTimeout(callback, 0)
}
}
const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"
class MYPromise {
state = PENDING
result = undefined
#handlers = []
constructor(func) {
const resolve = (result) => {
if (this.state === PENDING) {
this.state = FULFILLED
this.result = result
this.#handlers.forEach(({ onFulfilled }) => {
onFulfilled(this.result)
})
}
}
const reject = (result) => {
if (this.state === PENDING) {
this.state = REJECTED
this.result = result
this.#handlers.forEach(({ onRejected }) => {
onRejected(this.result)
})
}
}
func(resolve, reject)
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
const p2 = new MYPromise((resolve, reject) => {
if (this.state === FULFILLED) {
runAsynctask(() => {
try {
const x = onFulfilled(this.result)
// 1.处理返回Promise
if (x instanceof MYPromise) {
// console.log('MYPromise实例')
// 2. 调用then方法
// x.then(res => console.log(res), err => console.log(err))
x.then(res => resolve(res), err => reject(err))
} else {
resolve(x)
}
} catch (error) {
reject(error)
}
})
} else if (this.state === REJECTED) {
runAsynctask(() => {
onRejected(this.result)
})
} else if (this.state === PENDING) {
this.#handlers.push({
onFulfilled: () => {
runAsynctask(() => {
onFulfilled(this.result)
})
}, onRejected: () => {
runAsynctask(() => {
onRejected(this.result)
})
}
})
}
})
return p2
}
}
(八)链式编程-fulfilled状态-重复引用 需求:
then中返回的then方法返回的Promise实例报错- 注:下列代码中的
p2
const p = new MYPromise((resolve, reject) => {
resolve(1)
})
const p2 = p.then(res => {
return p2
})
p2.then(
res => { },
err => console.log('err:', err))
实现步骤
- 判断是否相同,抛出异常
// 封装的异步函数
function runAsynctask(callback) {
if (typeof queueMicrotask === 'function') {
queueMicrotask(callback)
} else if (typeof MutationObserver === 'function') {
const obs = new MutationObserver(callback)
const divNode = document.createElement('div')
obs.observe(divNode, { childList: true })
divNode.innerText = '监测元素改变,才会执行'
} else {
setTimeout(callback, 0)
}
}
const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"
class MYPromise {
state = PENDING
result = undefined
#handlers = []
constructor(func) {
const resolve = (result) => {
if (this.state === PENDING) {
this.state = FULFILLED
this.result = result
this.#handlers.forEach(({ onFulfilled }) => {
onFulfilled(this.result)
})
}
}
const reject = (result) => {
if (this.state === PENDING) {
this.state = REJECTED
this.result = result
this.#handlers.forEach(({ onRejected }) => {
onRejected(this.result)
})
}
}
func(resolve, reject)
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
const p2 = new MYPromise((resolve, reject) => {
if (this.state === FULFILLED) {
runAsynctask(() => {
try {
const x = onFulfilled(this.result)
// 1. 处理重复引用
if (x === p2) {
// console.log('返回了p2')
// 2. 抛出错误 Chaining cycle detected for promise #<Promise>
throw new TypeError('Chaining cycle detected for promise #<Promise>')
}
if (x instanceof MYPromise) {
x.then(res => resolve(res), err => reject(err))
} else {
resolve(x)
}
} catch (error) {
reject(error)
}
})
} else if (this.state === REJECTED) {
runAsynctask(() => {
onRejected(this.result)
})
} else if (this.state === PENDING) {
this.#handlers.push({
onFulfilled: () => {
runAsynctask(() => {
onFulfilled(this.result)
})
}, onRejected: () => {
runAsynctask(() => {
onRejected(this.result)
})
}
})
}
})
return p2
}
}
(八)链式编程-rejected状态
rejected状态和fulfilled状态处理方式是一样的。 需求
then的第二个回调函数,执行reject时的链式编程
const p = new MYPromise((resolve, reject) => {
reject(1)
})
const p2 = p.then(undefined, err => {
throw 'error'
// return p2
// return 2
// return new MYPromise((resolve, reject) => {
// resolve('MYPromise-2')
// })
})
p2.then(res => {
console.log('p2-res:', res)
}, err => {
console.log('p2-err:', err)
})
实现步骤
- 处理异常:
onRejected的异常 - 获取返回值:
onRejected的返回值 - 将
fulfilled状态中的处理逻辑抽取为函数resolvePromise并复用 fulfilled和rejected状态中调用函数resolvePromise
// 封装的异步函数
function runAsynctask(callback) {
if (typeof queueMicrotask === 'function') {
queueMicrotask(callback)
} else if (typeof MutationObserver === 'function') {
const obs = new MutationObserver(callback)
const divNode = document.createElement('div')
obs.observe(divNode, { childList: true })
divNode.innerText = '监测元素改变,才会执行'
} else {
setTimeout(callback, 0)
}
}
// 3. 抽取函数
function resolvePromise(p2, x, resolve, reject) {
if (x === p2) {
throw new TypeError('Chaining cycle detected for promise #<Promise>')
}
if (x instanceof MYPromise) {
x.then(res => resolve(res), err => reject(err))
} else {
resolve(x)
}
}
const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"
class MYPromise {
state = PENDING
result = undefined
#handlers = []
constructor(func) {
const resolve = (result) => {
if (this.state === PENDING) {
this.state = FULFILLED
this.result = result
this.#handlers.forEach(({ onFulfilled }) => {
onFulfilled(this.result)
})
}
}
const reject = (result) => {
if (this.state === PENDING) {
this.state = REJECTED
this.result = result
this.#handlers.forEach(({ onRejected }) => {
onRejected(this.result)
})
}
}
func(resolve, reject)
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
const p2 = new MYPromise((resolve, reject) => {
if (this.state === FULFILLED) {
runAsynctask(() => {
try {
const x = onFulfilled(this.result)
// 4. 调用函数
resolvePromise(p2, x, resolve, reject)
// if (x === p2) {
// throw new TypeError('Chaining cycle detected for promise #<Promise>')
// }
// if (x instanceof MYPromise) {
// x.then(res => resolve(res), err => reject(err))
// } else {
// resolve(x)
// }
} catch (error) {
reject(error)
}
})
} else if (this.state === REJECTED) {
runAsynctask(() => {
// 1. 处理异常
try {
// 2. 获取返回值
const x = onRejected(this.result)
// console.log('x:', x)
// 4. 调用函数
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
} else if (this.state === PENDING) {
this.#handlers.push({
onFulfilled: () => {
runAsynctask(() => {
onFulfilled(this.result)
})
}, onRejected: () => {
runAsynctask(() => {
onRejected(this.result)
})
}
})
}
})
return p2
}
}
(九)链式编程-pending状态
pending状态与rejected状态、fulfilled状态处理方式是一样的。
需求
then的第二个回调函数,执行reject时的链式编程
const p = new MYPromise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 2000)
})
const p2 = p.then(res => {
throw 'error'
// return p2
// return 2
// return new MYPromise((resolve, reject) => {
// resolve('resolve-2')
// // reject('reject-2')
// })
})
p2.then(res => {
console.log('p2-res:', res)
}, err => {
console.log('p2-err:', err)
})
实现步骤
- 处理异常:
onRejected的异常 - 获取返回值:
onRejected的返回值 - 将
fulfilled状态中的处理逻辑抽取为函数resolvePromise并复用 fulfilled和rejected状态中调用函数resolvePromise
// 封装的异步函数
function runAsynctask(callback) {
if (typeof queueMicrotask === 'function') {
queueMicrotask(callback)
} else if (typeof MutationObserver === 'function') {
const obs = new MutationObserver(callback)
const divNode = document.createElement('div')
obs.observe(divNode, { childList: true })
divNode.innerText = '监测元素改变,才会执行'
} else {
setTimeout(callback, 0)
}
}
// 抽取函数
function resolvePromise(p2, x, resolve, reject) {
if (x === p2) {
throw new TypeError('Chaining cycle detected for promise #<Promise>')
}
if (x instanceof MYPromise) {
x.then(res => resolve(res), err => reject(err))
} else {
resolve(x)
}
}
const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"
class MYPromise {
state = PENDING
result = undefined
#handlers = []
constructor(func) {
const resolve = (result) => {
if (this.state === PENDING) {
this.state = FULFILLED
this.result = result
this.#handlers.forEach(({ onFulfilled }) => {
onFulfilled(this.result)
})
}
}
const reject = (result) => {
if (this.state === PENDING) {
this.state = REJECTED
this.result = result
this.#handlers.forEach(({ onRejected }) => {
onRejected(this.result)
})
}
}
func(resolve, reject)
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
const p2 = new MYPromise((resolve, reject) => {
if (this.state === FULFILLED) {
runAsynctask(() => {
try {
const x = onFulfilled(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
} else if (this.state === REJECTED) {
runAsynctask(() => {
try {
const x = onRejected(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
} else if (this.state === PENDING) {
this.#handlers.push({
onFulfilled: () => {
runAsynctask(() => {
// 1. 处理异常
try {
// 2.获取返回值
const x = onFulfilled(this.result)
// 3.调用函数
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}, onRejected: () => {
runAsynctask(() => {
// 1. 处理异常
try {
// 2.获取返回值
const x = onRejected(this.result)
// 3.调用函数
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
})
}
})
return p2
}
}
(十)总结—附完整版代码
以上为自定义Promise核心功能,面试手写一般到这里就可以 完整代码
// 封装的异步函数
function runAsynctask(callback) {
if (typeof queueMicrotask === 'function') {
queueMicrotask(callback)
} else if (typeof MutationObserver === 'function') {
const obs = new MutationObserver(callback)
const divNode = document.createElement('div')
obs.observe(divNode, { childList: true })
divNode.innerText = '监测元素改变,才会执行'
} else {
setTimeout(callback, 0)
}
}
// 抽取函数
function resolvePromise(p2, x, resolve, reject) {
if (x === p2) {
throw new TypeError('Chaining cycle detected for promise #<Promise>')
}
if (x instanceof MYPromise) {
x.then(res => resolve(res), err => reject(err))
} else {
resolve(x)
}
}
const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"
class MYPromise {
state = PENDING
result = undefined
#handlers = []
constructor(func) {
const resolve = (result) => {
if (this.state === PENDING) {
this.state = FULFILLED
this.result = result
this.#handlers.forEach(({ onFulfilled }) => {
onFulfilled(this.result)
})
}
}
const reject = (result) => {
if (this.state === PENDING) {
this.state = REJECTED
this.result = result
this.#handlers.forEach(({ onRejected }) => {
onRejected(this.result)
})
}
}
func(resolve, reject)
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
const p2 = new MYPromise((resolve, reject) => {
if (this.state === FULFILLED) {
runAsynctask(() => {
try {
const x = onFulfilled(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
} else if (this.state === REJECTED) {
runAsynctask(() => {
try {
const x = onRejected(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
} else if (this.state === PENDING) {
this.#handlers.push({
onFulfilled: () => {
runAsynctask(() => {
try {
const x = onFulfilled(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}, onRejected: () => {
runAsynctask(() => {
try {
const x = onRejected(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
})
}
})
return p2
}
}
三、自定义Promise实例方法和静态方法
(一)实例方法-catch
需求:
- 实现实例方法
catch,可以实现如下调用
const p = new MYPromise((resolve, reject) => {
reject('reject-error')
// throw 'throw-error'
})
p.then(res => {
console.log('res:', res)
}).catch(err => {
console.log('err:', err)
})
实现步骤
- 参考文档,catch等同于:
then(undefined,onRjected) - 直接添加
catch方法,内部调用then - 使用
try-catch包裹constructor中的func捕获异常
// 封装的异步函数
function runAsynctask(callback) {
if (typeof queueMicrotask === 'function') {
queueMicrotask(callback)
} else if (typeof MutationObserver === 'function') {
const obs = new MutationObserver(callback)
const divNode = document.createElement('div')
obs.observe(divNode, { childList: true })
divNode.innerText = '监测元素改变,才会执行'
} else {
setTimeout(callback, 0)
}
}
// 抽取函数
function resolvePromise(p2, x, resolve, reject) {
if (x === p2) {
throw new TypeError('Chaining cycle detected for promise #<Promise>')
}
if (x instanceof MYPromise) {
x.then(res => resolve(res), err => reject(err))
} else {
resolve(x)
}
}
const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"
class MYPromise {
state = PENDING
result = undefined
#handlers = []
constructor(func) {
const resolve = (result) => {
if (this.state === PENDING) {
this.state = FULFILLED
this.result = result
this.#handlers.forEach(({ onFulfilled }) => {
onFulfilled(this.result)
})
}
}
const reject = (result) => {
if (this.state === PENDING) {
this.state = REJECTED
this.result = result
this.#handlers.forEach(({ onRejected }) => {
onRejected(this.result)
})
}
}
func(resolve, reject)
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
const p2 = new MYPromise((resolve, reject) => {
if (this.state === FULFILLED) {
runAsynctask(() => {
try {
const x = onFulfilled(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
} else if (this.state === REJECTED) {
runAsynctask(() => {
try {
const x = onRejected(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
} else if (this.state === PENDING) {
this.#handlers.push({
onFulfilled: () => {
runAsynctask(() => {
try {
const x = onFulfilled(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}, onRejected: () => {
runAsynctask(() => {
try {
const x = onRejected(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
})
}
})
return p2
}
/**
* catch方法
* 1. 内部调用then方法
* 2. 处理异常
* */
catch(onRejected) {
// 1. 内部调用then方法
return this.then(undefined, onRejected)
}
}
// ------------- 实例化测试 -------------
const p = new MYPromise((resolve, reject) => {
// reject('reject-error')
throw 'throw-error'
})
p.then(res => {
console.log('res:', res)
}).catch(err => {
console.log('err:', err)
})
(二)实例方法-finally
finally和catch处理方式是一样的,只是接收的参数不一样 需求:
- 无论成功失败都会执行
finally的回调函数 - 回调函数不接受任何参数
实现步骤
参考文档:finally方法类似于调用then(onFinally,onFinally),且不接受任何回调函数
// 封装的异步函数
function runAsynctask(callback) {
if (typeof queueMicrotask === 'function') {
queueMicrotask(callback)
} else if (typeof MutationObserver === 'function') {
const obs = new MutationObserver(callback)
const divNode = document.createElement('div')
obs.observe(divNode, { childList: true })
divNode.innerText = '监测元素改变,才会执行'
} else {
setTimeout(callback, 0)
}
}
// 抽取函数
function resolvePromise(p2, x, resolve, reject) {
if (x === p2) {
throw new TypeError('Chaining cycle detected for promise #<Promise>')
}
if (x instanceof MYPromise) {
x.then(res => resolve(res), err => reject(err))
} else {
resolve(x)
}
}
const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"
class MYPromise {
state = PENDING
result = undefined
#handlers = []
constructor(func) {
const resolve = (result) => {
if (this.state === PENDING) {
this.state = FULFILLED
this.result = result
this.#handlers.forEach(({ onFulfilled }) => {
onFulfilled(this.result)
})
}
}
const reject = (result) => {
if (this.state === PENDING) {
this.state = REJECTED
this.result = result
this.#handlers.forEach(({ onRejected }) => {
onRejected(this.result)
})
}
}
func(resolve, reject)
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
const p2 = new MYPromise((resolve, reject) => {
if (this.state === FULFILLED) {
runAsynctask(() => {
try {
const x = onFulfilled(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
} else if (this.state === REJECTED) {
runAsynctask(() => {
try {
const x = onRejected(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
} else if (this.state === PENDING) {
this.#handlers.push({
onFulfilled: () => {
runAsynctask(() => {
try {
const x = onFulfilled(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}, onRejected: () => {
runAsynctask(() => {
try {
const x = onRejected(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
})
}
})
return p2
}
catch(onRejected) {
return this.then(undefined, onRejected)
}
/**
* finally方法
* 1. 内部调用then方法
* */
finally(onFinally) {
return this.then(onFinally, onFinally)
}
}
// ------------- 实例化测试 -------------
const p = new MYPromise((resolve, reject) => {
// resolve('resolve-res')
// reject('reject-error')
// throw 'throw-error'
})
p.then(res => {
console.log('res:', res)
}).catch(err => {
console.log('err:', err)
}).finally(() => {
console.log('finally')
})
(三)静态方法-resolve
Class(类)的方法都会被实例继承,但是对于在方法名前面加了static关键字的方法,则不能直接被实例继承,只能通过类来调用,称之为“静态方法”。 需求
- 将给定的值转换为一个 Promise,返回一个带有成功原因的Promise对象
MYPromise.resolve(new MYPromise((resolve, reject) => {
// resolve('resolve')
// reject('reject')
// throw 'error'
})).then(res => {
console.log('res:', res)
}, err => {
console.log('err:', err)
})
MYPromise.resolve('测试').then(res => {
console.log(res)
})
实现步骤
- 通过
static关键字添加静态方法resolve,接收参数value - 内部判断传入的值
- 如果是
Promise实例,直接返回 - 其他的值,创建
Promise实例并返回,内部通过resolve(value)传递value
// 封装的异步函数
function runAsynctask(callback) {
if (typeof queueMicrotask === 'function') {
queueMicrotask(callback)
} else if (typeof MutationObserver === 'function') {
const obs = new MutationObserver(callback)
const divNode = document.createElement('div')
obs.observe(divNode, { childList: true })
divNode.innerText = '监测元素改变,才会执行'
} else {
setTimeout(callback, 0)
}
}
// 抽取函数
function resolvePromise(p2, x, resolve, reject) {
if (x === p2) {
throw new TypeError('Chaining cycle detected for promise #<Promise>')
}
if (x instanceof MYPromise) {
x.then(res => resolve(res), err => reject(err))
} else {
resolve(x)
}
}
const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"
class MYPromise {
state = PENDING
result = undefined
#handlers = []
constructor(func) {
const resolve = (result) => {
if (this.state === PENDING) {
this.state = FULFILLED
this.result = result
this.#handlers.forEach(({ onFulfilled }) => {
onFulfilled(this.result)
})
}
}
const reject = (result) => {
if (this.state === PENDING) {
this.state = REJECTED
this.result = result
this.#handlers.forEach(({ onRejected }) => {
onRejected(this.result)
})
}
}
func(resolve, reject)
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
const p2 = new MYPromise((resolve, reject) => {
if (this.state === FULFILLED) {
runAsynctask(() => {
try {
const x = onFulfilled(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
} else if (this.state === REJECTED) {
runAsynctask(() => {
try {
const x = onRejected(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
} else if (this.state === PENDING) {
this.#handlers.push({
onFulfilled: () => {
runAsynctask(() => {
try {
const x = onFulfilled(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}, onRejected: () => {
runAsynctask(() => {
try {
const x = onRejected(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
})
}
})
return p2
}
catch(onRejected) {
return this.then(undefined, onRejected)
}
finally(onFinally) {
return this.then(onFinally, onFinally)
}
/**
* 静态方法-resolve
* */
static resolve(value) {
// 1 Promise直接返回
if (value instanceof MYPromise) {
return value;
}
// 2 转为Promise并返回(fulfilled状态)
return new MYPromise((resolve, reject) => {
resolve(value);
});
}
}
// ------------- 测试 -------------
MYPromise.resolve(new MYPromise((resolve, reject) => {
// resolve('resolve')
// reject('reject')
// throw 'error'
})).then(res => {
console.log('res:', res)
}, err => {
console.log('err:', err)
})
MYPromise.resolve('测试').then(res => {
console.log(res)
})
(四)静态方法-reject
需求
- 返回一个已拒绝(rejected)的 Promise 对象
实现步骤
- 添加静态方法
- 返回
rejected状态的Promise
// 封装的异步函数
function runAsynctask(callback) {
if (typeof queueMicrotask === 'function') {
queueMicrotask(callback)
} else if (typeof MutationObserver === 'function') {
const obs = new MutationObserver(callback)
const divNode = document.createElement('div')
obs.observe(divNode, { childList: true })
divNode.innerText = '监测元素改变,才会执行'
} else {
setTimeout(callback, 0)
}
}
// 抽取函数
function resolvePromise(p2, x, resolve, reject) {
if (x === p2) {
throw new TypeError('Chaining cycle detected for promise #<Promise>')
}
if (x instanceof MYPromise) {
x.then(res => resolve(res), err => reject(err))
} else {
resolve(x)
}
}
const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"
class MYPromise {
state = PENDING
result = undefined
#handlers = []
constructor(func) {
const resolve = (result) => {
if (this.state === PENDING) {
this.state = FULFILLED
this.result = result
this.#handlers.forEach(({ onFulfilled }) => {
onFulfilled(this.result)
})
}
}
const reject = (result) => {
if (this.state === PENDING) {
this.state = REJECTED
this.result = result
this.#handlers.forEach(({ onRejected }) => {
onRejected(this.result)
})
}
}
func(resolve, reject)
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
const p2 = new MYPromise((resolve, reject) => {
if (this.state === FULFILLED) {
runAsynctask(() => {
try {
const x = onFulfilled(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
} else if (this.state === REJECTED) {
runAsynctask(() => {
try {
const x = onRejected(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
} else if (this.state === PENDING) {
this.#handlers.push({
onFulfilled: () => {
runAsynctask(() => {
try {
const x = onFulfilled(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}, onRejected: () => {
runAsynctask(() => {
try {
const x = onRejected(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
})
}
})
return p2
}
catch(onRejected) {
return this.then(undefined, onRejected)
}
finally(onFinally) {
return this.then(onFinally, onFinally)
}
static resolve(value) {
if (value instanceof MYPromise) {
return value;
}
return new MYPromise((resolve, reject) => {
resolve(value);
});
}
/**
* 静态方法-reject
* 1. 返回rejected状态的Promise
* */
static reject(value) {
return new MYPromise((resolve,reject)=>{
reject(value)
})
}
}
// ------------- 测试代码 -------------
MYPromise.reject("error22").catch((res) => {
console.log(res);
});
(五)静态方法-race
需求:
- 接收Promise数组,数组中第一个Promise敲定时,获取成功/失败结果
- 传入的参数不是数组,直接报错
实现步骤
- 返回
Promise - 判断是否未数组,不是直接报错
- 等待第一个敲定
// 封装的异步函数
function runAsynctask(callback) {
if (typeof queueMicrotask === 'function') {
queueMicrotask(callback)
} else if (typeof MutationObserver === 'function') {
const obs = new MutationObserver(callback)
const divNode = document.createElement('div')
obs.observe(divNode, { childList: true })
divNode.innerText = '监测元素改变,才会执行'
} else {
setTimeout(callback, 0)
}
}
// 抽取函数
function resolvePromise(p2, x, resolve, reject) {
if (x === p2) {
throw new TypeError('Chaining cycle detected for promise #<Promise>')
}
if (x instanceof MYPromise) {
x.then(res => resolve(res), err => reject(err))
} else {
resolve(x)
}
}
const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"
class MYPromise {
state = PENDING
result = undefined
#handlers = []
constructor(func) {
const resolve = (result) => {
if (this.state === PENDING) {
this.state = FULFILLED
this.result = result
this.#handlers.forEach(({ onFulfilled }) => {
onFulfilled(this.result)
})
}
}
const reject = (result) => {
if (this.state === PENDING) {
this.state = REJECTED
this.result = result
this.#handlers.forEach(({ onRejected }) => {
onRejected(this.result)
})
}
}
func(resolve, reject)
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
const p2 = new MYPromise((resolve, reject) => {
if (this.state === FULFILLED) {
runAsynctask(() => {
try {
const x = onFulfilled(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
} else if (this.state === REJECTED) {
runAsynctask(() => {
try {
const x = onRejected(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
} else if (this.state === PENDING) {
this.#handlers.push({
onFulfilled: () => {
runAsynctask(() => {
try {
const x = onFulfilled(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}, onRejected: () => {
runAsynctask(() => {
try {
const x = onRejected(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
})
}
})
return p2
}
catch(onRejected) {
return this.then(undefined, onRejected)
}
finally(onFinally) {
return this.then(onFinally, onFinally)
}
static resolve(value) {
if (value instanceof MYPromise) {
return value;
}
return new MYPromise((resolve, reject) => {
resolve(value);
});
}
static reject(value) {
return new MYPromise((resolve,reject)=>{
reject(value)
})
}
/**
* 静态方法-race
* 1. 返回Promise
* 2. 判断是否为数组 错误信息:Argument is not iterable
* 3. 等待第一个敲定
* */
static race(promise) {
return new MYPromise((resolve, reject) => {
// 2. 判断是否为数组
if (!Array.isArray(promise)) {
return reject(new TypeError("Argument is not iterable"));
}
// 3. 等待第一个敲定
promise.forEach((p) => {
MYPromise.resolve(p).then(
(res) => {
resolve(res);
},
(err) => {
reject(err);
}
);
});
});
}
}
// ------------- 测试代码 -------------
const p1 = new MYPromise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 2000)
})
const p2 = new MYPromise((resolve, reject) => {
setTimeout(() => {
reject(2)
}, 1000)
})
MYPromise.race([p1, p2, '测试']).then((res) => {
console.log('res:', res) // 测试
}, err => {
console.log('err:', err)
})
(六)静态方法-all
需求:
- 接收Promise数组
- 所有Promise都成功时,返回一个成功的Promise对象及成功数组
- 任何一个Promise失败,返回一个失败的Promise对象及第一个失败原因
实现步骤
- 添加静态方法
all - 内部返回
Promise实例,在返回的Promise实例中:- 判断参数是否为数组,不是通过
reject传递错误 - 空数组直接以空数组为结果进行兑现
- 遍历
Promise数组,通过resolve静态方法等待结果- 处理全部兑现:
- 通过数组记录结果,用索引的方式来添加,目的是保证结果的顺序和
Promise数组的顺序一致 - 通过兑现次数进行判断,因为是通过索引的方式记录结果,如果第一次兑现的是最后一个,那么数组的长度就已经和Promise数组的长度一致了,所以需要通过兑现次数来进行判断
- 通过数组记录结果,用索引的方式来添加,目的是保证结果的顺序和
- 任意一个拒绝,调用
reject传递拒绝原因
- 处理全部兑现:
- 判断参数是否为数组,不是通过
// 封装的异步函数
function runAsynctask(callback) {
if (typeof queueMicrotask === 'function') {
queueMicrotask(callback)
} else if (typeof MutationObserver === 'function') {
const obs = new MutationObserver(callback)
const divNode = document.createElement('div')
obs.observe(divNode, { childList: true })
divNode.innerText = '监测元素改变,才会执行'
} else {
setTimeout(callback, 0)
}
}
// 抽取函数
function resolvePromise(p2, x, resolve, reject) {
if (x === p2) {
throw new TypeError('Chaining cycle detected for promise #<Promise>')
}
if (x instanceof MYPromise) {
x.then(res => resolve(res), err => reject(err))
} else {
resolve(x)
}
}
const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"
class MYPromise {
state = PENDING
result = undefined
#handlers = []
constructor(func) {
const resolve = (result) => {
if (this.state === PENDING) {
this.state = FULFILLED
this.result = result
this.#handlers.forEach(({ onFulfilled }) => {
onFulfilled(this.result)
})
}
}
const reject = (result) => {
if (this.state === PENDING) {
this.state = REJECTED
this.result = result
this.#handlers.forEach(({ onRejected }) => {
onRejected(this.result)
})
}
}
func(resolve, reject)
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
const p2 = new MYPromise((resolve, reject) => {
if (this.state === FULFILLED) {
runAsynctask(() => {
try {
const x = onFulfilled(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
} else if (this.state === REJECTED) {
runAsynctask(() => {
try {
const x = onRejected(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
} else if (this.state === PENDING) {
this.#handlers.push({
onFulfilled: () => {
runAsynctask(() => {
try {
const x = onFulfilled(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}, onRejected: () => {
runAsynctask(() => {
try {
const x = onRejected(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
})
}
})
return p2
}
catch(onRejected) {
return this.then(undefined, onRejected)
}
finally(onFinally) {
return this.then(onFinally, onFinally)
}
static resolve(value) {
if (value instanceof MYPromise) {
return value;
}
return new MYPromise((resolve, reject) => {
resolve(value);
});
}
static reject(value) {
return new MYPromise((resolve,reject)=>{
reject(value)
})
}
static race(promise) {
return new MYPromise((resolve, reject) => {
if (!Array.isArray(promise)) {
return reject(new TypeError("Argument is not iterable"));
}
promise.forEach((p) => {
MYPromise.resolve(p).then(
(res) => {
resolve(res);
},
(err) => {
reject(err);
}
);
});
});
}
/**
* 静态方法-all
* 1. 返回Promise实例
* 2. 判断是否为数组 错误信息:Argument is not iterable
* 3. 空数组直接兑现
* 4. 处理全部兑现
* 4.1 记录结果:索引来记录,保证结果的顺序和Promise数组的顺序一致
* 4.2 判断全部兑现:通过兑现的次数进行判断,保证可以获取到所有的结果
* 5. 处理第一个拒绝
* */
static all(promises) {
// 1. 返回Promise实例
return new MYPromise((resolve, reject) => {
// 2. 判断是否为数组 错误信息:Argument is not iterable
if (!Array.isArray(promises)) {
return reject(new TypeError("Argument is not iterable"));
}
// 3. 空数组直接兑现
promises.length === 0 && resolve(promises);
// 4. 处理全部兑现
const result = [];
let count = 0;
promises.forEach((p, index) => {
MYPromise.resolve(p).then(
(res) => {
// 4.1 记录结果:索引来记录,保证结果的顺序和Promise数组的顺序一致
result[index] = p;
// 4.2 判断全部兑现:通过兑现的次数进行判断,保证可以获取到所有的结果
count++;
count === promises.length && resolve(result);
},
(err) => {
// 5. 处理第一个拒绝
reject(err)
}
);
});
});
}
}
// ------------- 测试代码 -------------
const p1 = MYPromise.resolve(1);
const p2 = new MYPromise((resolve, reject) => {
setTimeout(() => {
// resolve(2)
reject("error");
}, 1000);
});
const p3 = 3;
MYPromise.all([p1, p2, p3]).then(
(res) => {
// MYPromise.all().then(res => {
// MYPromise.all([]).then(res => {
console.log("res:", res);
},
(err) => {
console.log("err:", err);
}
);
(七)静态方法-allSettled
需求
- 传入
Promise数组,当所有对象都已敲定时 - 返回一个新的
Promise对象及以数组形式保存的结果
实现步骤
做法和all方法类似,区别是要获取全部敲定的结果(成功/拒绝),以及获取的结果是对象形式
- 添加静态方法
allSettled - 内部返回
Promise实例,在返回的Promise实例中: - 判断参数是否为数组,不是通过
reject传递错误 - 空数组直接以空数组为结果进行兑现
- 遍历
Promise数组,通过resolve静态方法等待敲定结果 - 等待全部敲定:并记录结果,根据兑现和拒绝将如下格式的内容通过索引的方式的记录到数组中
- 处理兑现:
{state:FULFILLED,value:'xxx'} - 处理拒绝:
{state:REJECTED,reason:'xxx'} - 根据敲定的次数判断是否全部敲定,全部敲定之后,通过
resolve传递结果数组
// 封装的异步函数
function runAsynctask(callback) {
if (typeof queueMicrotask === 'function') {
queueMicrotask(callback)
} else if (typeof MutationObserver === 'function') {
const obs = new MutationObserver(callback)
const divNode = document.createElement('div')
obs.observe(divNode, { childList: true })
divNode.innerText = '监测元素改变,才会执行'
} else {
setTimeout(callback, 0)
}
}
// 抽取函数
function resolvePromise(p2, x, resolve, reject) {
if (x === p2) {
throw new TypeError('Chaining cycle detected for promise #<Promise>')
}
if (x instanceof MYPromise) {
x.then(res => resolve(res), err => reject(err))
} else {
resolve(x)
}
}
const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"
class MYPromise {
state = PENDING
result = undefined
#handlers = []
constructor(func) {
const resolve = (result) => {
if (this.state === PENDING) {
this.state = FULFILLED
this.result = result
this.#handlers.forEach(({ onFulfilled }) => {
onFulfilled(this.result)
})
}
}
const reject = (result) => {
if (this.state === PENDING) {
this.state = REJECTED
this.result = result
this.#handlers.forEach(({ onRejected }) => {
onRejected(this.result)
})
}
}
func(resolve, reject)
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
const p2 = new MYPromise((resolve, reject) => {
if (this.state === FULFILLED) {
runAsynctask(() => {
try {
const x = onFulfilled(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
} else if (this.state === REJECTED) {
runAsynctask(() => {
try {
const x = onRejected(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
} else if (this.state === PENDING) {
this.#handlers.push({
onFulfilled: () => {
runAsynctask(() => {
try {
const x = onFulfilled(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}, onRejected: () => {
runAsynctask(() => {
try {
const x = onRejected(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
})
}
})
return p2
}
catch(onRejected) {
return this.then(undefined, onRejected)
}
finally(onFinally) {
return this.then(onFinally, onFinally)
}
static resolve(value) {
if (value instanceof MYPromise) {
return value;
}
return new MYPromise((resolve, reject) => {
resolve(value);
});
}
static reject(value) {
return new MYPromise((resolve,reject)=>{
reject(value)
})
}
static race(promise) {
return new MYPromise((resolve, reject) => {
if (!Array.isArray(promise)) {
return reject(new TypeError("Argument is not iterable"));
}
promise.forEach((p) => {
MYPromise.resolve(p).then(
(res) => {
resolve(res);
},
(err) => {
reject(err);
}
);
});
});
}
static all(promises) {
return new MYPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject(new TypeError("Argument is not iterable"));
}
promises.length === 0 && resolve(promises);
const result = [];
let count = 0;
promises.forEach((p, index) => {
MYPromise.resolve(p).then(
(res) => {
result[index] = p;
count++;
count === promises.length && resolve(result);
},
(err) => {
reject(err)
}
);
});
});
}
/**
* 静态方法-allSettled
* 1. 返回Promise
* 2. 数组判断 错误信息: Argument is not iterable
* 3. 为空直接敲定
* 4. 等待全部敲定
* 4.1 记录结果
* 4.2 处理兑现{status:'fulfilled',value:''}
* 4.3 处理拒绝{status:'rejected',reason:''}
* */
static allSettled(promises) {
return new MYPromise((resolve, reject) => {
// 2. 数组判断 错误信息: Argument is not iterable
if (!Array.isArray(promises)) {
return reject(new TypeError("Argument is not iterable"));
}
// 3. 为空直接敲定
promises.length === 0 && resolve(promises);
// 4. 等待全部敲定
const result = [];
let count = 0;
promises.forEach((p, index) => {
MYPromise.resolve(p).then(
(res) => {
// 4.1 记录结果:索引来记录,保证结果的顺序和Promise数组的顺序一致
result[index] = { status: FULFILLED, value: res };
count++
count === promises.length && resolve(result);
},
(err) => {
result[index] = { status: REJECTED, reason: err };
count++
count === promises.length && resolve(result);
}
);
});
});
}
// ------------- 测试代码 -------------
const p1 = MYPromise.resolve(1);
const p2 = new MYPromise((resolve, reject) => {
setTimeout(() => {
// resolve(2)
reject("error");
}, 1000);
});
const p3 = 3;
MYPromise.all([p1, p2, p3]).then(
(res) => {
// MYPromise.all().then(res => {
// MYPromise.all([]).then(res => {
console.log("res:", res);
},
(err) => {
console.log("err:", err);
}
);
(八)静态方法-any
需求
- 传入Promise数组,
- 任何一个Promise对象敲定时,返回一个新的Promise对象,及对应的结果
- 所有Promise都被拒绝时,返回一个包含所有拒绝原因的AggregateError错误数组
实现步骤
做法和all方法也有点类似,区别是获取第一个兑现,或者是全部拒绝
- 添加静态方法
any - 内部返回
Promise实例,在返回的Promise实例中:- 判断参数是否为数组,不是通过
reject传递错误 - 空数组直接以空数组为结果进行兑现
- 判断参数是否为数组,不是通过
- 遍历
Promise数组,通过resolve静态方法等待结果- 第一个兑现,通过
resolve传递兑现结果 - 全部拒绝:
- 定义数组,保存拒绝原因,通过索引记录,目的是保证顺序和
Promise数组一致 - 通过次数判断是否全部拒绝,当全部拒绝时,通过
reject传递AggregateError类型的错误,并将拒绝原因数组传递进去即可
- 定义数组,保存拒绝原因,通过索引记录,目的是保证顺序和
- 第一个兑现,通过
// 封装的异步函数
function runAsynctask(callback) {
if (typeof queueMicrotask === 'function') {
queueMicrotask(callback)
} else if (typeof MutationObserver === 'function') {
const obs = new MutationObserver(callback)
const divNode = document.createElement('div')
obs.observe(divNode, { childList: true })
divNode.innerText = '监测元素改变,才会执行'
} else {
setTimeout(callback, 0)
}
}
// 抽取函数
function resolvePromise(p2, x, resolve, reject) {
if (x === p2) {
throw new TypeError('Chaining cycle detected for promise #<Promise>')
}
if (x instanceof MYPromise) {
x.then(res => resolve(res), err => reject(err))
} else {
resolve(x)
}
}
const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"
class MYPromise {
state = PENDING
result = undefined
#handlers = []
constructor(func) {
const resolve = (result) => {
if (this.state === PENDING) {
this.state = FULFILLED
this.result = result
this.#handlers.forEach(({ onFulfilled }) => {
onFulfilled(this.result)
})
}
}
const reject = (result) => {
if (this.state === PENDING) {
this.state = REJECTED
this.result = result
this.#handlers.forEach(({ onRejected }) => {
onRejected(this.result)
})
}
}
func(resolve, reject)
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
const p2 = new MYPromise((resolve, reject) => {
if (this.state === FULFILLED) {
runAsynctask(() => {
try {
const x = onFulfilled(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
} else if (this.state === REJECTED) {
runAsynctask(() => {
try {
const x = onRejected(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
} else if (this.state === PENDING) {
this.#handlers.push({
onFulfilled: () => {
runAsynctask(() => {
try {
const x = onFulfilled(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}, onRejected: () => {
runAsynctask(() => {
try {
const x = onRejected(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
})
}
})
return p2
}
catch(onRejected) {
return this.then(undefined, onRejected)
}
finally(onFinally) {
return this.then(onFinally, onFinally)
}
static resolve(value) {
if (value instanceof MYPromise) {
return value;
}
return new MYPromise((resolve, reject) => {
resolve(value);
});
}
static reject(value) {
return new MYPromise((resolve,reject)=>{
reject(value)
})
}
static race(promise) {
return new MYPromise((resolve, reject) => {
if (!Array.isArray(promise)) {
return reject(new TypeError("Argument is not iterable"));
}
promise.forEach((p) => {
MYPromise.resolve(p).then(
(res) => {
resolve(res);
},
(err) => {
reject(err);
}
);
});
});
}
static all(promises) {
return new MYPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject(new TypeError("Argument is not iterable"));
}
promises.length === 0 && resolve(promises);
const result = [];
let count = 0;
promises.forEach((p, index) => {
MYPromise.resolve(p).then(
(res) => {
result[index] = p;
count++;
count === promises.length && resolve(result);
},
(err) => {
reject(err)
}
);
});
});
}
static allSettled(promises) {
return new MYPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject(new TypeError("Argument is not iterable"));
}
promises.length === 0 && resolve(promises);
const result = [];
let count = 0;
promises.forEach((p, index) => {
MYPromise.resolve(p).then(
(res) => {
result[index] = { status: FULFILLED, value: res };
count++
count === promises.length && resolve(result);
},
(err) => {
result[index] = { status: REJECTED, reason: err };
count++
count === promises.length && resolve(result);
}
);
});
});
}
/**
* 静态方法-any
* 1. 返回Promise,数组判断 错误信息: Argument is not iterable
* 2. 空数组直接拒绝 AggregateError([错误原因1..],All promises were rejected)
* 3. 等待结果
* 3.1 第一个兑现
* 3.2 全部拒绝
*/
static any(promises) {
return new MYPromise((resolve, reject) => {
// 1. 返回Promise,数组判断 错误信息: Argument is not iterable
if (!Array.isArray(promises)) {
return reject(new TypeError("Argument is not iterable"));
}
// 2. 空数组直接拒绝 AggregateError([错误原因1..],All promises were rejected)
promises.length === 0 &&
reject(
new AggregateError(promises, "All promises were rejected")
);
// 3.等待结果
const errors = [];
let count = 0;
promises.forEach((p, index) => {
MYPromise.resolve(p).then(
(res) => {
// 3.1 第一个兑现
resolve(res);
},
(err) => {
// 3.2 全部拒绝
errors[index] = err;
count++;
count === promises.length &&
reject(
new AggregateError(errors, "All promises were rejected")
);
}
);
});
});
}
}
// ------------- 测试代码 -------------
const p1 = new MYPromise((resolve, reject) => {
setTimeout(() => {
reject(1);
}, 2000);
});
// const p2 = 2
const p2 = MYPromise.reject(2);
const p3 = new MYPromise((resolve, reject) => {
setTimeout(() => {
// resolve(3)
reject(3);
}, 1000);
});
MYPromise.any([p1, p2, p3]).then(
(res) => {
// MYPromise.any().then(res => {
// MYPromise.any([]).then(res => {
console.log("res:", res);
},
(err) => {
console.dir(err);
}
);
(九)总结—附完整版代码
自定义promise现在已经是面试必备手写题了,每个面试者都需要掌握
// 封装的异步函数
function runAsynctask(callback) {
if (typeof queueMicrotask === 'function') {
queueMicrotask(callback)
} else if (typeof MutationObserver === 'function') {
const obs = new MutationObserver(callback)
const divNode = document.createElement('div')
obs.observe(divNode, { childList: true })
divNode.innerText = '监测元素改变,才会执行'
} else {
setTimeout(callback, 0)
}
}
// 抽取函数
function resolvePromise(p2, x, resolve, reject) {
if (x === p2) {
throw new TypeError('Chaining cycle detected for promise #<Promise>')
}
if (x instanceof MYPromise) {
x.then(res => resolve(res), err => reject(err))
} else {
resolve(x)
}
}
const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"
class MYPromise {
state = PENDING
result = undefined
#handlers = []
constructor(func) {
const resolve = (result) => {
if (this.state === PENDING) {
this.state = FULFILLED
this.result = result
this.#handlers.forEach(({ onFulfilled }) => {
onFulfilled(this.result)
})
}
}
const reject = (result) => {
if (this.state === PENDING) {
this.state = REJECTED
this.result = result
this.#handlers.forEach(({ onRejected }) => {
onRejected(this.result)
})
}
}
func(resolve, reject)
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
const p2 = new MYPromise((resolve, reject) => {
if (this.state === FULFILLED) {
runAsynctask(() => {
try {
const x = onFulfilled(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
} else if (this.state === REJECTED) {
runAsynctask(() => {
try {
const x = onRejected(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
} else if (this.state === PENDING) {
this.#handlers.push({
onFulfilled: () => {
runAsynctask(() => {
try {
const x = onFulfilled(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}, onRejected: () => {
runAsynctask(() => {
try {
const x = onRejected(this.result)
resolvePromise(p2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
})
}
})
return p2
}
catch(onRejected) {
return this.then(undefined, onRejected)
}
finally(onFinally) {
return this.then(onFinally, onFinally)
}
static resolve(value) {
if (value instanceof MYPromise) {
return value;
}
return new MYPromise((resolve, reject) => {
resolve(value);
});
}
static reject(value) {
return new MYPromise((resolve,reject)=>{
reject(value)
})
}
static race(promise) {
return new MYPromise((resolve, reject) => {
if (!Array.isArray(promise)) {
return reject(new TypeError("Argument is not iterable"));
}
promise.forEach((p) => {
MYPromise.resolve(p).then(
(res) => {
resolve(res);
},
(err) => {
reject(err);
}
);
});
});
}
static all(promises) {
return new MYPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject(new TypeError("Argument is not iterable"));
}
promises.length === 0 && resolve(promises);
const result = [];
let count = 0;
promises.forEach((p, index) => {
MYPromise.resolve(p).then(
(res) => {
result[index] = p;
count++;
count === promises.length && resolve(result);
},
(err) => {
reject(err)
}
);
});
});
}
static allSettled(promises) {
return new MYPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject(new TypeError("Argument is not iterable"));
}
promises.length === 0 && resolve(promises);
const result = [];
let count = 0;
promises.forEach((p, index) => {
MYPromise.resolve(p).then(
(res) => {
result[index] = { status: FULFILLED, value: res };
count++
count === promises.length && resolve(result);
},
(err) => {
result[index] = { status: REJECTED, reason: err };
count++
count === promises.length && resolve(result);
}
);
});
});
}
static any(promises) {
return new MYPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject(new TypeError("Argument is not iterable"));
}
promises.length === 0 &&
reject(
new AggregateError(promises, "All promises were rejected")
);
const errors = [];
let count = 0;
promises.forEach((p, index) => {
MYPromise.resolve(p).then(
(res) => {
resolve(res);
},
(err) => {
errors[index] = err;
count++;
count === promises.length &&
reject(
new AggregateError(errors, "All promises were rejected")
);
}
);
});
});
}
}
(十)最新特性补充
最新特性补充 Promise.withResolvers()
Promise.withResolvers() // 完全等同于以下代码
let resolve, reject;
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
这里我们可以看到,如果我们想使用promise 的内部res和rej,需要定义变量来接收,Promise.withResolvers()返回一个对象,可以直接来调用,但需要浏览器注意兼容性
const {promise,resovle,reject} = Promise.withResolvers()
function func(){
resolve('调用了')
}
func()
promise.then(res=>{
console.log(res)
})