const PADDING = 'padding'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MPromise {
state = PADDING // 初始化为padding状态
result = undefined // 初始化结果数据
// 定义私有属性
#cacheCallbacks = [] // 【cacheCallbacks】存储回调数据 格式:[{onFulfilled, onRejected}]
constructor(fn) {
// 定义reslove方法,更新状态
const reslove = (value) => {
if (this.state === PADDING) {
this.state = FULFILLED // 更新状态为fulfilled
this.result = value // 保存成功结果数据
// 执行异步成功后,调用缓存的.then传入的回调数据执行
this.#cacheCallbacks.forEach(({ onFulfilled }) => { // 解构、获取成功的回调
onFulfilled(this.result)
})
// console.log('reslove方法:', this.result)
}
}
// 定义reject方法,更新状态
const reject = (value) => {
if (this.state === PADDING) {
this.state = REJECTED // 更新状态为rejected
this.result = value // 保存失败结果数据
// 执行异步成功后,调用缓存的.then传入的回调数据执行
this.#cacheCallbacks.forEach(({ onRejected }) => { // 解构、获取失败的回调
onRejected(this.result)
})
// console.log('reject方法:', this.result)
}
}
try {
// 将reslove函数,reject函数作为入参调用传入的fn函数
fn(reslove, reject)
} catch (error) {
// catch时直接调用reject函数
reject(error)
}
}
// 定义then方法接收 一个【成功的回调】与一个【失败的回调】
then(onFulfilled, onRejected) {
// 如果传入的是函数就赋值函数,如果是基本类型则赋值个新函数并返回传入的值
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (res) => res
onRejected = typeof onRejected === 'function' ? onRejected : (res) => { throw res }
// 新的promise实例
const p2 = new MPromise((reslove_, reject_) => { // 链式调用返回一个新的Promise实例
switch (this.state) {
case FULFILLED:
// 使用自定义【runAsyncTast】异步执行函数封装
runAsyncTast(() => {
try {
// 拿到上次的调用结果
const res = onFulfilled(this.result)
// 校验结果逻辑统一处理
reslovePromise(p2, res, reslove_, reject_)
} catch (error) {
// 捕获异常
reject_(error)
}
})
break
case REJECTED:
// 使用自定义【runAsyncTast】异步执行函数封装
runAsyncTast(() => {
// 处理异常
try {
// 拿到上次的调用结果
const res = onRejected(this.result)
// 校验结果逻辑统一处理
reslovePromise(p2, res, reslove_, reject_)
} catch (error) {
reject_(error)
}
})
break
case PADDING:
// 初始化状态缓存.then函数调用时传入的数据
this.#cacheCallbacks.push({
// 将onFulfilled赋值一个函数,函数体使用自定义【runAsyncTast】异步执行函数封装
onFulfilled: () => runAsyncTast(() => {
try {
const res = onFulfilled(this.result)
reslovePromise(p2, res, reslove_, reject_)
} catch (error) {
reject_(error)
}
}),
// 将onRejected赋值一个函数,函数体使用自定义【runAsyncTast】异步执行函数封装
onRejected: () => runAsyncTast(() => {
try {
const res = onRejected(this.result)
reslovePromise(p2, res, reslove_, reject_)
} catch (error) {
reject_(error)
}
})
})
break
}
})
return p2 // 返回新的promise实例
}
// 定义catch,等同于执行.then的第二个onRejected回调
catch(onRejected_) {
// .catch时,将传入回调函数传入到then函数的【第二个参数】中捕获捕获异常
return this.then(undefined, onRejected_)
}
// 定义finally,等同于执行.then的onFulfilled函数的执行
finally(onFulfilled_) {
// .finally时,将传入回调函数分别传入到then函数的俩个形参中执行
return this.then(onFulfilled_, onFulfilled_)
}
// 静态方法【reslove】实现
static reslove(value) {
// 校验传入值,如果是Promise则直接返回
if (value instanceof MPromise) {
return value
} else {
// 如果是值类型,这转为promise并返回fulfilled状态
return new MPromise((reslove) => {
reslove(value)
})
}
}
// 静态方法【reject】实现
static reject(value) {
return new MPromise((undefined, reject) => {
reject(value)
})
}
// 静态方法【race】实现
static race(promises) {
// 返回一个promise实例
return new MPromise((reslove, reject) => {
// 校验参数是否为数组,如果不是则抛出异常
if (!Array.isArray(promises)) {
return reject(new TypeError('传入参数是不可迭代的!'))
}
// 等待第一个执行结果敲定,无论是【成功】还是【失败】结果都返回
promises.forEach(promise => {
// 由于传入的参数类型不确定,所以使用【.reslove】方法处理结果
MPromise.reslove(promise).then((res) => reslove(res), (err) => reject(err))
})
})
}
// 静态方法【all】实现
static all(promises) {
// Promise.all()静态方法接受一个Promise可迭代对象作为输入,并返回一个promise
return new MPromise((reslove, reject) => {
// 校验参数是否为数组,如果不是则抛出异常
if (!Array.isArray(promises)) {
return reject(new TypeError('传入参数是不可迭代的!'))
}
if (promises.length === 0) {
return reslove(promises)
}
let num = 0
const arr = []
// 当所有输入的Promise 都被兑现时,返回的 Promise也将被兑现(即使传入的是一个空的可迭代对象),并返回一个包含所有兑现值的数组。
promises.forEach((promise, index) => {
// 由于传入的参数类型不确定,所以使用【.reslove】方法处理结果
MPromise.reslove(promise).then((res) => {
arr[index] = res
num += 1
if (num === promises.length) {
reslove(arr)
}
}, (err) => reject(err)) // 如果输入的任何 Promise被拒绝,则返回的 Promise将被拒绝,并带有第一个被拒绝的原因。
})
})
}
// 静态方法【allSettled】 只有所有的结果都敲定才能返回所有的结果
static allSettled(promises) {
// 返回一个promise
return new MPromise((reslove, reject) => {
if (!Array.isArray(promises)) {
return reject(new TypeError('传入参数是不可迭代的!'))
}
if (promises.length === 0) {
return reslove(promises)
}
let num = 0
const arr = []
promises.forEach((promise, index) => {
MPromise.reslove(promise).then(res => {
arr[index] = {
status: FULFILLED,
value: res
}
promises.length === ++num && reslove(arr)
}, err => {
arr[index] = {
status: REJECTED,
reason: err
}
promises.length === ++num && reslove(arr)
})
})
})
}
// 静态方法【any】获取第一个成功的结果,或者获取所有失败的结果,抛出【AggregateError:所有承诺都被拒绝了】
static any(promises) {
return new MPromise((reslove, reject) => {
// 不传数组,直接报错
if (!Array.isArray(promises)) {
return reject(new TypeError('传入参数是不可迭代的!'))
}
// 如果传入空数组,直接拒绝抛出【AggregateError:所有承诺都被拒绝了】
if (promises.length === 0) {
return reject(new AggregateError(promises, '所有承诺都被拒绝了'))
}
const arr = []
let num = 0
promises.forEach((promise, index) => {
MPromise.reslove(promise).then(res => {
reslove(res)
}, err => {
arr[index] = err
promises.length === ++num && reject(new AggregateError(arr, '所有承诺都被拒绝了'))
})
})
})
}
}
// 抽取公共方法
function reslovePromise(p2, reslut, reslove_, reject_) {
// 校验是否是循环引用返回结果
if (reslut === p2) {
// alert('检测到promise #< promise >的链接循环')
throw new TypeError('检测到promise #< promise >的链接循环')
}
// 针对返回结果进行判断,如还是promise实例就执行.then获取执行结果后,再把结果返回
if (reslut instanceof MPromise) {
reslut.then((reslove__) => {
// 上次执行结果,成功的逻辑
reslove_(reslove__)
}, (reject__) => {
// 上次执行结果,失败的逻辑
reject_(reject__)
})
} else {
// 如果返回值不是promise实例
reslove_(reslut) // 将结果传入到下一个.then函数回调中
}
}
/*
* 异步执行函数封装
* @parameter callback 需要异步执行的回调函数
*/
function runAsyncTast(callback) {
if (typeof queueMicrotask === 'function') { // 判断兼容性,是否有原生异步任务 【queueMicrotask】
queueMicrotask(callback)
} else if (typeof MutationObserver === 'function') { // 判断兼容性,是否有MutationObserver
// 创建观察器 【MutationObserver】
const obs = new MutationObserver(callback)
const divNode = document.createElement('div') // 创建一个任意标签,【不需要添加到页面上】
obs.observe(divNode, { childList: true }) // 给新建的标签节点添加监听事件
divNode.innerText = 'MutationObserver come' // 给标签赋值, 触发监听函数执行
} else {
setTimeout(callback, 0)
}
}
手写promise
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
推荐阅读更多精彩内容
- promise promise.all promise.allSettled promise.race
- Promise概念 Promise是异步编程的一种解决方案,将异步操作以同步的流程表达出来,避免了层层嵌套的回调函...
- 咱们书接上文( 点我查看[//www.greatytc.com/p/565ad78b4b3b] ),继续...
- promise的术语 promise 是一个有then方法的对象或者是函数,行为遵循本规范 thenable 是一...
- 咱们书接上文( 点我查看[//www.greatytc.com/p/5a03197461d8] ),继续...