手写Promise
// 手写Promise
class HandwrittenPromise {
static PENDING = "待定";
static FUFILLED = "成功";
static REJECTED = "失败";
constructor(func) {
// 初始化状态为 pending
this.status = HandwrittenPromise.PENDING;
// 初始化成功状态的值
this.result = "";
// 初始化失败状态的值
this.reason = "";
// 存储成功状态的回调函数 多次调用then时用数组保存
this.resolveCallbacks = [];
// 存储失败状态的回调函数 多次调用then时用数组保存
this.rejectCallbacks = [];
try {
/*
HandwrittenPromise实例的参数函数体内部调用传入的resolve和reject方法时,方法内的this并不指向实例对象
所以要在传参数时将方法绑定上this
*/
func(this.resolve.bind(this), this.reject.bind(this))
} catch (error) {
// 当HandwrittenPromise实例参数函数体中抛出错误时,调用reject,状态变为REJECTED
this.reject(error)
}
}
resolve(result) {
// 只有pending状态才可改变,如果resolve()后边写了reject(),则状态不会由fufilled转为rejected
if (this.status === HandwrittenPromise.PENDING) {
queueMicrotask(() => {
if (this.status !== HandwrittenPromise.PENDING) return //避免 调用resolve 后又调用 reject 多次执行
this.status = HandwrittenPromise.FUFILLED;
this.result = result;
this.resolveCallbacks.forEach((callback) => { //循环依次调用
callback(this.result);
})
})
}
}
reject(reason) {
// 只有pending状态才可改变
if (this.status === HandwrittenPromise.PENDING) {
queueMicrotask(() => {//执行then方法时将resolve或者reject添加到异步队列,queueMicrotask: 主线程执行完毕之后立马执行
if (this.status !== HandwrittenPromise.PENDING) return
this.status = HandwrittenPromise.REJECTED;
this.reason = reason;
this.rejectCallbacks.forEach((callback) => {
callback(this.reason);
})
})
}
}
then(onFUFILLED, onREJECTED) {
// 返回HandwrittenPromise实例,方便链式调用
return new HandwrittenPromise((resolve, reject) => { //返回一个HandwrittenPromise,实现链式调用
// 如果传入的参数不是函数,则将参数改为一个函数,防止调用函数时找不到函数名的报错
onFUFILLED = typeof onFUFILLED === "function" ? onFUFILLED : (result) => { result }
onREJECTED = typeof onREJECTED === "function" ? onREJECTED : (reason) => { throw reason }
/*
当 then 方法被调用时,我们首先需要判断原始 Promise 对象的状态。
如果原始 Promise 对象的状态为 fulfilled,那么我们就可以直接执行成功回调函数,并将成功状态的值作为参数传递给它。
如果原始 Promise 对象的状态为 rejected,那么我们就可以直接执行失败回调函数,并将失败原因作为参数传递给它。
但是,如果原始 Promise 对象的状态为 pending,那么我们就需要等待原始 Promise 对象的状态发生变化,再执行相应的操作。
*/
if (this.status === HandwrittenPromise.PENDING) {
this.resolveCallbacks.push(() => {
try { //异常处理:若成功则继续执行then链式调用的第一个回调,失败则执行then的第二个回调
const x = onFUFILLED(this.result) //如果实例对象调用resolve,then方法将回调函数onFUFILLED的返回值传给resolve,resolve()方法再传递下去
resolve(x)
} catch (error) {
reject(error) //如果回调函数onFUFILLED内部抛出异常,将异常结果传给reject,reject(error)方法再传递下去,链式调用的下一个then执行第二个回调
}
})
this.rejectCallbacks.push(() => {
try {
const x = onREJECTED(this.reason) //如果实例对象调用reject,then方法仍然将回调函数onREJECTED的返回值传给resolve,resolve()方法再传递下去
resolve(x)
} catch (error) {
reject(error) //如果回调函数onREJECTED内部抛出异常,将异常结果传给reject,执行reject(error)
}
});
}
// 如果我们执行then的时候,他的状态已经不是pending的时候,如:
/*
const promise = new myPromise((resolve, reject) => {
console.log("状态pending")
resolve(1111)
reject(2222)
})
// 调用then方法多次调用
promise.then(res => {
console.log("res1:", res)
}, err => {
console.log("err:", err)
})
promise.then(res => {
console.log("res2:", res)
}, err => {
console.log("err2:", err)
})
//仔细看这里 上面的代码是同步的 执行会被添加到对应的数组里面依次调用,调用完毕后,他的状态是不是就已经确定好了
//然后你再执行下面的这个异步代码 那这个时候状态已经被改变了,直接执行对应的状态回调即可
setTimeout(() => {
promise.then(res => {
console.log("res3:", res)
}, err => {
console.log("err3:", err)
})
}, 1000)
*/
// 如果在then调用的时候, 状态已经确定下来 那么就应该直接执行then里面回调,就不需要在push执行了
if (this.status === HandwrittenPromise.FUFILLED) {
setTimeout(() => {
try {
const x = onFUFILLED(this.result)
resolve(x)
} catch (error) {
reject(error)
}
})
}
if (this.status === HandwrittenPromise.REJECTED) {
setTimeout(() => {
try {
const x = onREJECTED(this.reason)
resolve(x)
} catch (error) {
reject(error)
}
})
}
})
}
catch(onREJECTED) {
return this.then(null, onREJECTED);
}
//finally函数无论成功或者失败都会调用,并且是在最后调用
//利用queueMicrotask最快处理微任务的特性,使finally(fn)传递过来的函数fn最后执行
finally(fn) {
setTimeout(() => {
fn()
}, 0)
}
}
评论
问答助学
相关内容
0个评论
全部评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
内容推荐
day75✅今天做了:看八股,梳理复习项目,leetcode2道⏰明天计划:继续加油
0
Day 00目前状态: 裸辞,基础差,经验少目标: 通过社招在杭州找到一份 Java 开发工作坚持每天发帖总结,一起加油 👍
0
Day1今天学习了java中if的使用
0
编程导航也是好起来了,在酷安打广告了😁
0
day 61今天来学校上课了,和教授谈了,可以接下RA工作,不过一周只能charge 10h, 工资很少,不过一个月600刀也勉强比没有好。今天的工作还没做完,最近在做知识库构造,Ui/UX上周就设计完,现在在做底座的建设今天也让Claude直接帮我把Neetcode150 题目+解题思路+代码给我整理了,我发现我真的只有找碎片化时间才能做题,我还不如先背先回忆(之前都做过)祝祖国母亲节日快乐,也
1
作者分享
有没有人做智能云图库的时候 删除图片时报“额度更新失败”的错误啊 我做前端,后端直接拉的代码 直接在接口文档测试也不能删除 怀疑是后端的问题
1
day7
找到图片上传失败的原因了 因为我是自己封装的Axios, 在上传图像的时候,需要把它转成formdata,然后再请求头设置form–data/multipart
明天开始图片创建页面的开发
1
day6
笔记与项目进度同步完成
图片模块没做多少 卡住了 上传图片报错500 接口文档测试是能上传的 不知道为啥一直报错 我看deepseek说前端还要写COS的逻辑,我看文字教程上也没写呀 有人解答一下吗啊啊啊啊
1
day5
同步笔记至用户注销部分
明日计划:将笔记同步至项目进度处,开始图片模块
3
day4
添加了用户权限控制 终于完成了用户模块
明天写一下笔记 然后再优化一下TODO
1
