目录
一:首先分析官方的promise
二:手写Promise-then方法设计
三:then方法优化:
四:Promise-catch方法设计
五:Promise-finally方法设计
//本文带大家实现一个基本的 promise 过多的边界情况就不在考虐,理解主要实现过程以及逻辑即可
//对于一个个出现的问题 我会逐步分析原因以及对应的解决思路
//前提是你必须掌握 promise的基本使用,以及回调函数有对应的理解
//第一步:初步实现一个最简单的Promise (循序渐进的方式往下编写,小白也能听懂,当然大神可直接跳过一些废话~~~ )
一:首先分析官方的promise
//---首先分析官方的promise
const p1 = new Promise((resolve, reject) => {
resolve(2222)
reject(33333)
})
// 调用then方法 then 方法接收2个回调函数作为参数
p1.then(res => { //只会打印222, 因为promise的状态一但由pending的状态改变了 就无法再次改变
console.log("res1:", res)
}, err => {
console.log("err:", err)
})
//解析:
//由此可见 promise 的参数 接收一个函数,在函数中又接收了2个回调函数 作为参数,然后调用resolve 方法
//在执行then方法。 then 函数又接收2个参数 均为回调函数,当执行 resolve(2222)后 就会来到then 的第一个参数 的回调函数
// 执行 reject(33333)后 就会来到then 的第二个参数回调函数-
//1.那么初步编写可得:
const PROMISE_STATUS_PENDING = 'pending' //定义三种状态常量
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
class myPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING //1.初始化状态 pending
this.value = undefined //2.保存参数
this.error = undefined
const resolve = ((value) => {
if (this.status === PROMISE_STATUS_PENDING) { //3. 只有pending状态才可改变
this.status = PROMISE_STATUS_FULFILLED
}
})
const reject = ((error) => {
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_REJECTED
}
})
executor(resolve, reject) //在new myPromise 时初始化立即调用传递过来的函数
}
}
二:手写Promise-then方法设计
//2. 执行resolve 或者 reject 会调用then 方法(在上面的代码基础改动)
class myPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.error = undefined
const resolve = ((value) => {
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_FULFILLED
this.resfn(value)
}
})
const reject = ((error) => {
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_REJECTED
this.errfn(error)
}
})
executor(resolve, reject)
}
then(resfn, errfn) { //4.then 方法接收2个回调函数作为 参数 : 第一个为成功的回调,第二个失败的回调
this.resfn = resfn
this.errfn = errfn
}
}
//(看代码是不是觉得最基本的实现了)接下来我们执行下自己实现的promise,看是否正常
const p1 = new myPromise((resolve, reject) => {
resolve(111)
})
p1.then(res => {
console.log(res);
}, err => {
})
//执行后你会发现报错了 错误信息: this.resfn is not a function
//那么为什么会报错呢? 因为和 代码的执行顺序有关 当我们 new myPromise()执行resolve 的时候就会来到resolve方法
//而你的then 方法鸭羹就没有执行到呢 所以就报错了
//解决方法: 只要让then 先执行就可以 , 将resolve 或者 reject 要执行then 方法时添加到异步队列即可
上代码:
class myPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.error = undefined
const resolve = ((value) => {
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_FULFILLED
//大家可能会想到使用setTimeout 然后0秒执行,但此处使用queueMicrotask 会更加合适
// setTimeout(() => {
// this.resfn(value)
// }, 0);
queueMicrotask(() => { //queueMicrotask: 主线程执行完毕之后立马执行
this.resfn(value)
})
}
})
const reject = ((error) => {
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_REJECTED
queueMicrotask(() => {
this.errfn(error)
})
}
})
executor(resolve, reject)
}
then(resfn, errfn) { //4.then 方法接收2个回调函数作为 参数 : 第一个为成功的回调,第二个失败的回调
this.resfn = resfn
this.errfn = errfn
}
}
//举一个栗子:
setTimeout(() => {
console.log('setTimeout');
}, 0);
queueMicrotask(() => {
console.log('queueMicrotask');
});
//实际运行
queueMicrotask
setTimeout
然后执行:
const p1 = new myPromise((resolve, reject) => {
resolve(111)
reject(333333)
})
p1.then(res => { //最终打印 1111
console.log(res);
}, err => {
console.log(err);
})
到这里 我们最简单的实现就以经完成了,接下来我们继续 优化then 方法:
class myPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.error = undefined
this.resfns = [] //1.多次调用then 时用数组 保存
this.errfns = []
const resolve = ((value) => {
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_FULFILLED
queueMicrotask(() => {
this.value = value
this.resfns.forEach(fn => { //循环依次调用
fn(this.value)
})
})
}
})
const reject = ((error) => {
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_REJECTED
queueMicrotask(() => {
this.error = error
this.errfns.forEach(fn => {
fn(this.error)
})
})
}
})
executor(resolve, reject)
}
then(resfn, errfn) { //将多次调用的then 方法保存到数组中,依次调用
this.resfns.push(resfn)
this.errfns.push(errfn)
}
}
class myPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.error = undefined
this.resfns = [] //1.多次调用then 时用数组 保存
this.errfns = []
const resolve = ((value) => {
if (this.status === PROMISE_STATUS_PENDING) {
queueMicrotask(() => {
this.status = PROMISE_STATUS_FULFILLED
this.value = value
this.resfns.forEach(fn => {
fn(this.value)
})
})
}
})
const reject = ((error) => {
if (this.status === PROMISE_STATUS_PENDING) {
queueMicrotask(() => {
this.status = PROMISE_STATUS_REJECTED
this.error = error
this.errfns.forEach(fn => {
fn(this.error)
})
})
}
})
executor(resolve, reject)
}
then(resfn, errfn) {
// 1.如果在then调用的时候, 状态已经确定下来,那么就可以直接调用
if (this.status === PROMISE_STATUS_FULFILLED && resfn) {
resfn(this.value)
}
if (this.status === PROMISE_STATUS_REJECTED && errfn) {
errfn(this.error)
}
//2. 相反 对与已经确定的状态 就不需要在push 执行了
if (this.status === PROMISE_STATUS_PENDING) {
this.resfns.push(resfn)
this.errfns.push(errfn)
}
}
}
执行:
const p1 = new myPromise((resolve, reject) => {
resolve(111)
// reject(333333)
})
p1.then(res => {
console.log("res1:", res)
}, err => {
console.log("err1:", err)
})
// 调用then方法多次调用
p1.then(res => {
console.log("res2:", res)
}, err => {
console.log("err2:", err)
})
// 在确定Promise状态之后, 再次调用then
setTimeout(() => {
p1.then(res => {
console.log("res3:", res)
}, err => {
console.log("err3:", err)
})
}, 1000)
结果:
res1: 111
res2: 111
res3: 111
三:then方法优化:
对于我们之前 的then方法多次调用是通过实例化出来的类 调用的
例如:
p1.then(res => {
console.log("res1:", res)
}, err => {
console.log("err1:", err)
})
p1.then(res => {
console.log("res2:", res)
}, err => {
console.log("err2:", err)
})
这样子调用以我们目前的代码是可以实现的,但是如果是 一直链式调用下去呢?废话少说上代码:
const p1 = new myPromise((resolve, reject) => {
resolve(111)
reject(333333)
})
p1.then(res => {
console.log("第一次的成功回调:", res)
return "第二次的成功回调"
}, err => {
console.log("err1:", err)
return "第二次的失败回调"
}).then(res => {
console.log("res2:", res)
}, err => {
console.log("err2:", err)
})
现在我们代码肯定是走不通的(可以拿去自己的环境测试下)接下来继续优化我们的代码:
优化之前首先要分析一波: (已官方的promise链式调用为示例来解释)
1. 执行resolve
2. 调用then 方法,then方法返回的值 实则是 new myPromse((resolve,reject) => resolve("第二次的成功回调")),将返回值 用resolve()方法再传递下去
所以在打印完 "第一次的成功回调:",111 的时候 再次打印 "res2:",第二次的成功回调,
3. 那么什么时候才会打印 "err2:"第二次的失败回调 呢?只需要在第一次调用then 的时候 抛出异常 就会执行err2 了
例如:
p1.then(res => {
console.log("第一次的成功回调:", res)
throw new Error("err message")
}, err => {
console.log("err1:", err)
return "第二次的失败回调"
}).then(res => {
console.log("res2:", res)
}, err => {
console.log("err2:", err)
})
执行结果:
"第一次的成功回调:", 111
"err2: Error: err message
2.如果是执行reject ,在reject的第二个回调中
err => {
console.log("err1:", err)
return "第二次的失败回调"
}
return 了值那么接下来是 会执行 console.log("res2:", res) 还是 console.log("err2:", err) 呢?
例如:
const p1 = new myPromise((resolve, reject) => {
reject(333333)
})
p1.then(res => {
console.log("第一次的成功回调:", res)
return "第二次的成功回调"
}, err => {
console.log("err1:", err)
return "第二次的失败回调"
}).then(res => {
console.log("res2:", res)
}, err => {
console.log("err2:", err)
})
这里我先告诉你 其实会执行 console.log("res2:", res) ,如果想执行 console.log("err2:", err) 锁在的代码块,需要将 return "第二次的失败回调" 改为抛出异常 才会执行
栗子:
p1.then(res => {
console.log("第一次的成功回调:", res)
return "第二次的成功回调"
}, err => {
console.log("err1:", err)
throw new Error("err message")
}).then(res => {
console.log("res2:", res)
}, err => {
console.log("err2:", err)
})
逻辑已经理清楚 接下来用代码来表达:(可以复制下面这坨代码,然后用上面说的案例来自己测试 就比较清楚了)文章来源:https://www.toymoban.com/news/detail-560202.html
class myPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.error = undefined
this.resfns = []
this.errfns = []
const resolve = ((value) => {
if (this.status === PROMISE_STATUS_PENDING) {
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return //避免 调用resolve 后又调用 reject 多次执行
this.status = PROMISE_STATUS_FULFILLED
this.value = value
this.resfns.forEach(fn => {
fn(this.value)
})
})
}
})
const reject = ((error) => {
if (this.status === PROMISE_STATUS_PENDING) {
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_REJECTED
this.error = error
this.errfns.forEach(fn => {
fn(this.error)
})
})
}
})
executor(resolve, reject)
}
then(resfn, errfn) {
return new myPromise((resolve, reject) => { //1. 直接new 一个mypromise 作为then 方法的返回值 既可实现 .then.then.thne.then.....等等链式调用
if (this.status === PROMISE_STATUS_FULFILLED && resfn) {
try { //2. 异常处理:若成功则继续执行then链式调用 的第一个回调,失败则执行then 的第二个回调
const value = resfn(this.value)
resolve(value)
} catch (err) {
reject(err)
}
}
if (this.status === PROMISE_STATUS_REJECTED && errfn) {
try {
const value = errfn(this.error)
resolve(value)
} catch (err) {
reject(err)
}
}
if (this.status === PROMISE_STATUS_PENDING) {
this.resfns.push(() => { //push 回调函数
try {
const value = resfn(this.value)
resolve(value)
} catch (err) {
reject(err)
}
})
this.errfns.push(() => {
try {
const value = errfn(this.error)
resolve(value)
} catch (err) {
reject(err)
}
})
}
})
}
}
//然后测试:
const p1 = new myPromise((resolve, reject) => {
// resolve(111)
reject(333333)
})
p1.then(res => {
console.log("res1:", res)
return "第二次的成功回调"
}, err => {
console.log("err1:", err)
throw new Error("err message")
// return "第二次的失败回调"
}).then(res => {
console.log("res2:", res)
}, err => {
console.log("err2:", err)
})
四:Promise-catch方法设计
class myPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.error = undefined
this.resfns = []
this.errfns = []
const resolve = ((value) => {
if (this.status === PROMISE_STATUS_PENDING) {
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return //避免 调用resolve 后又调用 reject 多次执行
this.status = PROMISE_STATUS_FULFILLED
this.value = value
this.resfns.forEach(fn => {
fn(this.value)
})
})
}
})
const reject = ((error) => {
if (this.status === PROMISE_STATUS_PENDING) {
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_REJECTED
this.error = error
this.errfns.forEach(fn => {
fn(this.error)
})
})
}
})
executor(resolve, reject)
}
then(resfn, errfn) {
// 1.难点:利用抛错让下一个promise的catch帮忙处理 防止catch方法让链式调用断层
const defaultOnRejected = err => {
throw err
}
errfn = errfn || defaultOnRejected
return new myPromise((resolve, reject) => {
if (this.status === PROMISE_STATUS_FULFILLED && resfn) {
try { //2. 异常处理:若成功则继续执行then链式调用 的第一个回调,失败则执行then 的第二个回调
const value = resfn(this.value)
resolve(value)
} catch (err) {
reject(err)
}
}
if (this.status === PROMISE_STATUS_REJECTED && errfn) {
try {
const value = errfn(this.error)
resolve(value)
} catch (err) {
reject(err)
}
}
if (this.status === PROMISE_STATUS_PENDING) {
if (resfn) {
this.resfns.push(() => { //push 回调函数
try {
const value = resfn(this.value)
resolve(value)
} catch (err) {
reject(err) //tips:****利用抛出的错误 使得下一个promise的catch帮忙处理
}
})
}
if (errfn) {
this.errfns.push(() => {
try {
const value = errfn(this.error)
resolve(value)
} catch (err) {
reject(err)
}
})
}
}
})
}
catch (errfn) { //2.catch 方法
return this.then(undefined, errfn)
}
}
//接着测试代码:
const p1 = new myPromise((resolve, reject) => {
reject(333333)
})
p1.then(res => {
console.log("res:", res)
}).catch(err => {
console.log("err:", err)
})
//结果:
err: 333333
五:Promise-finally方法设计
const PROMISE_STATUS_PENDING = 'pending' //定义三种状态常量
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
class myPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.error = undefined
this.resfns = []
this.errfns = []
const resolve = ((value) => {
if (this.status === PROMISE_STATUS_PENDING) {
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return //避免 调用resolve 后又调用 reject 多次执行
this.status = PROMISE_STATUS_FULFILLED
this.value = value
this.resfns.forEach(fn => {
fn(this.value)
})
})
}
})
const reject = ((error) => {
if (this.status === PROMISE_STATUS_PENDING) {
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_REJECTED
this.error = error
this.errfns.forEach(fn => {
fn(this.error)
})
})
}
})
executor(resolve, reject)
}
then(resfn, errfn) {
// 1.利用抛错让下一个promise的catch帮忙处理 防止catch方法让链式调用断层
const defaultOnRejected = err => {
throw err
}
errfn = errfn || defaultOnRejected
const defaultOnFulfilled = value => {
return value
}
resfn = resfn || defaultOnFulfilled
return new myPromise((resolve, reject) => { //1. 直接new 一个mypromise 作为then 方法的返回值 既可实现 .then.then.thne.then.....等等链式调用
if (this.status === PROMISE_STATUS_FULFILLED && resfn) {
try { //2. 异常处理:若成功则继续执行then链式调用 的第一个回调,失败则执行then 的第二个回调
const value = resfn(this.value)
resolve(value)
} catch (err) {
reject(err)
}
}
if (this.status === PROMISE_STATUS_REJECTED && errfn) {
try {
const value = errfn(this.error)
resolve(value)
} catch (err) {
reject(err)
}
}
if (this.status === PROMISE_STATUS_PENDING) {
if (resfn) {
this.resfns.push(() => { //push 回调函数
try {
const value = resfn(this.value)
resolve(value)
} catch (err) {
reject(err) //tips:****利用抛出的错误 使得下一个promise的catch帮忙处理
}
})
}
if (errfn) {
this.errfns.push(() => {
try {
const value = errfn(this.error)
resolve(value)
} catch (err) {
reject(err)
}
})
}
}
})
}
catch (errfn) { //2.catch 方法
return this.then(undefined, errfn)
}
finally(fn) {
setTimeout(() => {
fn()
}, 0)
}
}
剩下的都是些类方法 比较简单 这里就先不讲了~~拜拜~文章来源地址https://www.toymoban.com/news/detail-560202.html
到了这里,关于手写Promise的基本实现 (超详细)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!