// 异步执行 使用三种异步解决方案 queueMicrotask/MutationObserver/setTimeout 由于前面两种低版本浏览器不支持用setTimeout兜底
function runAsynctask (callback) {
// 如果当前浏览器支持queueMicortask 那么queueMicrotask==='function'成立 直接使用queueMicortask处理异步
if (typeof queueMicrotask === 'function') {
queueMicrotask(callback) //queueMicrotask是一个函数直接调用即可
// MutationObserver MutationObserver==='function'成立 MutationObserver
} else if (typeof MutationObserver === "function") {
// MutationObserver的使用 首先需要new MutationObserver 创建一个实例
// 通过这个实例的observe方法传入两个参数 第一个参数是一个节点 第二个参数是一个对象 需要设置为childList:true
// 当这个节点发生改变时触发这个MutationObserver 进而异步执行
const obs = new MutationObserver(callback)
const divNode = document.createElement("div")
obs.observe(divNode, { childList: true })
divNode.innerText = 'test'
} else {
// 最后使用setTimeout进行兜底 如果低版本的浏览器不支持前两种 直接使用setTimeout处理异步
setTimeout(callback)
}
}
// 封装重复引用报错
function resolvePromise (x, p2, resolve, reject) {
if (x === p2) {
// 如果返回的对象和引用的对象相同则抛出错误
throw new TypeError("Chaining cycle detected for promise #<Promise>")
}
// 如果返回的是一个Mypromise 则直接调用then方法
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 // 如果当前状态是pending的话 执行resolve时把当前状态置为fulfilled
this.result = result // 用result来接受resolve传入的值
this.#handlers.forEach(({ onFulfilled }) => {
onFulfilled(this.result)
}) //用来处理 多次调用的情况 就比如说在3s 之后才执行resolve
// 再次之前状态一直是pending,而且后面有好几个then,
// 这时就通过handlers先把所有的方法都存储起来,当状态改为fulfilled时遍历执行所有的resolve()
}
}
const reject = (result) => {
if (this.state === PENDING) {
this.state = REJECTED //如果当前状态是pending的话 执行reject时把当前状态置为rejected
this.result = result
this.#handlers.forEach(({ onRejected }) => {
onRejected(this.result)
})//用来处理 多次调用的情况 就比如说在3s 之后才执行reject
// 再次之前状态一直是pending,而且后面有好几个then,
// 这时就通过handlers先把所有的方法都存储起来,当状态改为fulfilled时遍历执行所有的reject()
}
}
try {
func(resolve, reject) //实例化Mypromise立即执行func()
} catch (error) {
reject(error) //如果报错 立即捕获错误并返回报错原因
}
}
//then 方法
then (onFulfilled, onRejected) {
// 根据MDN 仿写Promise 如果onFulfilled 不是一个函数 返回 x=>x
// 如果onRejected不是函数 返回 x=>{throw x}
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : x => x
onRejected = typeof onRejected === 'function' ? onRejected : x => { throw x }
// then的返回值是Promise 这里new 一个MyPromise用p2来接受 方便后面返回
const p2 = new MyPromise((resolve, reject) => {
if (this.state === FULFILLED) {
runAsynctask(() => {
try {
const x = onFulfilled(this.result)
resolvePromise(x, p2, resolve, reject)
} catch (error) {
reject(error)
}
})
}
else if (this.state === REJECTED) {
runAsynctask(() => {
try {
onRejected(this.result)
resolvePromise(x, p2, resolve, reject)
} catch (error) {
reject(error)
}
})
}
else if (this.state === PENDING) {
this.#handlers.push({
onFulfilled: () => {
runAsynctask(() => {
try {
const x = onFulfilled(this.result)
resolvePromise(x, p2, resolve, reject)
} catch (error) {
reject(error)
}
})
}
, onRejected: () => {
runAsynctask(() => {
try {
const x = onRejected(this.result)
resolvePromise(x, p2, resolve, reject)
} catch (error) {
reject(error)
}
})
}
})
}
})
return p2
}
catch (onRejected) {
return this.then(undefined, onRejected)
}
finally (onFulfilled) {
return this.then(onFulfilled, onFulfilled)
}
static resolve (value) {
//接受promise对象直接返回,如果不是promise 将其转为promise 并将传入的值作为resolve的参数
if (value instanceof MyPromise) {
return value
} else {
return new MyPromise((resolve, reject) => resolve(value))
}
}
static reject (value) {
return new MyPromise((resolve, reject) => reject(value))
}
static race (promises) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject(new TypeError('Argument is not iterable'))
}
promises.forEach(p => {
MyPromise.resolve(p).then(res => resolve(res), err => reject(err))
})
})
}
static all (promises) {
return MyPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
return reject(new TypeError('Argument is not iterable'))
}
promises.length === 0 && resolve(promises) //&& 短路运算符 如果前面为true 则执行后面的逻辑
const results = []
const count = 0 //记录兑现次数,当兑现次数与传入数组的长度一致时,results就拿到的所有的结果
promises.forEach((p, index) => {
MyPromise.resolve(p).then(
res => {
results[index] = res//index是为了保证结果的顺序与Promise数组的顺序一致
count++
count === promises.length && resolve(results)//如果全部兑现了就把results这个数组传递出去
}, err => {
reject(err)
}
)
})
})
}
static allSettled (promises) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
return resolve(new TypeError("Argument is not iterable"))
}
promises.length === 0 && resolve(promises)
let results = []
let count = 0
promises.forEach((p, index) => {
MyPromise.resolve(p).then(res => {
results[index] = { state: FULFILLED, value: res }
conut++
conut === promises.length && resolve(results)
}, err => {
results[index] = { state: REJECTED, value: err }
conut++
conut === promises.length && resolve(results)
})
})
})
}
static any (promises) {
return new MyPromise((resolve, reject) => {
if (!Array.isArray(promises)) {
return resolve(new TypeError('Argument is not iterable'))
}
promises.length === 0 && reject(new AggregateError(promises, "All promises were rejected"))
let 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(promises, "All promises were rejected"))
})
})
})
}
}
JS手写Promise 包含实例方法(catch,finally)和静态方法(resolve,reject,race,all,allSetted,any)
最新推荐文章于 2024-06-12 11:59:04 发布