为了向那道光亮奔过去,他敢往深渊里跳;
于是今天朝着Promise的实现前进吧,写了四个小时,终于完结撒花;
我知道大家没有耐心,当然我也坐的腰疼,直接上代码,跟着我的注释一行行看过去,保证门清
javascript
const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"
// 提前封装好一个判断promise的 这里不用instanceof 因为有可能在我们的then的参数中,有可能是别人或者自己的promise
const isPromise = value => {
return (
!!value &&
(typeof value === "object" || typeof value === "function") &&
typeof value.then === "function"
)
}
class MyPromise {
#state = PENDING // 当前执行状态
#result = undefined // 当前结果值
#handler = [] // 记录成功与失败回调的数组
constructor(executor) {
const resolve = value => {
// resolve之后去改变当前状态为成功 与当前成功的值
this.#changeState(value, FULFILLED)
}
const reject = reason => {
// reject之后去改变当前状态为失败 与当前错误的值
this.#changeState(reason, REJECTED)
}
try {
// 这里直接执行参数中的函数
executor(resolve, reject)
} catch (error) {
console.error(error)
// 这里try catch 错误就走reject
reject(error)
}
}
// 将传入的函数放到微队列中去执行
#runMicroTask(runTask) {
// 如果不兼容promise
if (typeof Promise === "function") {
return Promise.resolve().then(runTask)
}
// MutationObserver兼容性更好
if (typeof MutationObserver === "function") {
const ob = new MutationObserver(runTask)
const node = document.createTextNode("")
ob.observe(node, { characterData: true })
node.data = 1
return
}
// 如果是node环境
if (process.nextTick && typeof process.nextTick === "function") {
process.nextTick(runTask)
}
}
// 改变状态 保存此次的值 并且执行回调
#changeState(result, state) {
if (this.#state != PENDING) return
this.#state = state
this.#result = result
this.#run()
}
// 这里跑每次then后的回调
#runOne(callback, resolve, reject) {
// 这里主要是为了模拟微任务 都是伪代码
this.#runMicroTask(() => {
// 如果为函数
if (typeof callback === "function") {
try {
// 拿到函数的返回值
const data = callback(this.#result)
// 如果是promise包括别人封装的promise
if (isPromise(data)) {
console.log("data", data)
// 如果是promise那就直接去执行.then 函数
// 这里需要注意 这个resolve 是给下一个 所以这里这个resolve函数里带有上一次then返回来的值的!
/* 可以看这里的注释来理解
p.then(testMap.promiseTask, err => {
console.log("第一次err err", err)
throw "不好意思"
})
.then(
res => {
return new MyPromise(mySuc => {
console.log("第二次", res)
mySuc("MyPromise的值" + res)
})
},
err => {
console.log("第二次err err", err)
}
)
*/
data.then(resolve, reject)
} else {
// 否则就自行resolve 把then(suc=>return '结果值') 就把这个data结果值给下一次调用的then传递过去
resolve(data)
}
} catch (error) {
// 不用解释了吧
console.error(error)
reject(error)
}
} else {
// 如果不是函数 就直接执行resolve
const settled = this.#state === FULFILLED ? resolve : reject
settled(this.#result)
}
})
}
#run() {
if (this.#state === PENDING) return
/*
把下面的注释拿上来 主要为了能一次看懂不来回跳动
这里做push主要是
const p = new MyPromise之后
p.then(res=>fn1(res))
p.then(res=>fn2(res))
记录两次 fn1 与fn2
当然如果不是链式调用其实两次的拿到的回调值都是一样的
*/
while (this.#handler.length) {
// 这里需要注意的是resolve 与reject用的是实际then函数中传递的resolve与reject 不是当前类中的resolve
const { onFulfilled, onRejected, resolve, reject } =
this.#handler.shift()
// 这里主要是为了简化代码 传递了此次
this.#runOne(
this.#state === FULFILLED ? onFulfilled : onRejected,
resolve,
reject
)
}
}
then(onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
/*
这里做push主要是
const p = new MyPromise之后
p.then(res=>fn1(res))
p.then(res=>fn2(res))
记录两次 fn1 与fn2
当然如果不是链式调用其实两次的拿到的回调值都是一样的
*/
this.#handler.push({
onFulfilled,
onRejected,
resolve,
reject,
})
this.#run()
})
}
//catch方法的封装 catch 的话直接让它执行错误代码就好了
// 可不要以为有这样的代码比如Promise.catch 没有哈 都是new Promise的回调函数reject执行后的,所以这里只要让它有这个 reject方法就行了!
catch(onRejected) {
return this.then(undefined, onRejected)
}
//resolve方法的封装,凡是被static修饰的属性和方法都是静态方法和属性,只能被类名调用
//不能被实例化对象调用.同时也不能被子类继承,换句话说它属于当前这个类的.
static resolve(value) {
//返回结果为Promise对象
// 这里呢需要判断他是不是promise resolve中可能是个promise
return new MyPromise((resolve, reject) => {
if (isPromise(value)) {
value.then(
v => {
resolve(v)
},
r => {
reject(r)
}
)
} else {
resolve(value)
}
})
}
//reject方法的封装 reject都是出错这种明确值,所以这里不需要判断 你给啥,我给下一个error给啥
static reject(value) {
return new MyPromise((resolve, reject) => {
reject(value)
})
}
//all方法的封装
static all(promises) {
const self = this
return new MyPromise((resolve, reject) => {
let length = promises.length // 缓存一下有多少个promise
let count = 0 // 用于记录resolve的数量
let values = new Array(length) // 用于存储resolve返回的值
for (let i = 0; i < length; i++) {
let promise = promises[i]
// 判断数组的每一项,如果是promise,就进入then,不是就直接放进values数组中返回
if (isPromise(promise)) {
promise
.then(res => {
// 记录promise完成的数量
count++
// values存储每一个promise的res
values[i] = res
// 由于异步代码在最后执行,我们需要在then里面判断promise的完成数量,全部完成就resolve
// 在for外面判断,是防止它全部都不是promise实例
if (count === length) {
resolve(values)
}
})
.catch(err => {
// 当有一个promise实例reject,我们就直接reject
reject(err)
})
} else {
// 针对不是promise实例
count++
values[i] = promise
}
}
// 当数据的所有项都不是promise实例,我们就在这判断多一次,然后resolve
if (count === length) {
resolve(values)
}
})
}
//race方法的封装
static race(promises) {
return new MyPromise((resolve, reject) => {
const len = promises.length
for (let i = 0; i < len; i += 1) {
const promise = promises[i]
// 只要有一条成功则全部成功
promise.then(
res => {
resolve(res)
},
error => {
resolve(error)
}
)
}
})
}
}
window.MyPromise = MyPromise
const test1 = new MyPromise(suc => {
setTimeout(() => suc("成功 p"), 1001)
})
const test2 = new MyPromise((resolve, reject) => {
setTimeout(() => {
reject(3)
}, 1000)
})
const test3 = new MyPromise(suc => {
setTimeout(() => suc("成功 test3"), 1019)
})
MyPromise.all([test2, test1, test3])
.then(res => {
console.log("res all", res)
})
.catch(res => {
console.log("error", res)
})
MyPromise.race([test2, test1, test3])
.then(res => {
console.log("res race", res)
})
.catch(res => {
console.log("error", res)
})
const catchTest = new MyPromise((resolve, reject) => {
setTimeout(() => {
reject("catch 测试")
}, 1000)
}).catch(error => {
console.error(error)
})
const p = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(3)
}, 1000)
})
const testMap = {
promiseTask: res => {
console.log("第一次 ===>", res)
return new Promise(suc => {
suc("promise方式的res", res)
})
},
funcTask: res => {
console.log("第一次 ===>", res)
return res
},
// 直接穿透第一次resolve 或者reject 值到下一条then函数中
otherTask: "其他",
}
p.then(testMap.promiseTask, err => {
console.log("第一次err err", err)
throw "不好意思"
})
.then(
res => {
return new MyPromise(mySuc => {
console.log("第二次", res)
mySuc("MyPromise的值" + res)
})
},
err => {
console.log("第二次err err", err)
}
)
.then(
res => {
console.log("第三次", res)
return "第三次的值" + res
},
err => {
console.log("第三次err err", err)
}
)
.then(
res => {
console.log("第四次", res)
},
err => {
console.log("第四次err err", err)
}
)