当前位置: 首页 > news >正文

【前端】Promise对象的实现-JavaScript

完整代码:

class MyPromise {constructor(executor) {// 状态:pending、fulfilled、rejectedthis.state = 'pending';this.value = undefined; // 成功时的值this.reason = undefined; // 失败时的原因this.onFulfilledCallbacks = []; // 成功时的回调队列this.onRejectedCallbacks = []; // 失败时的回调队列const resolve = (value) => {if (this.state === 'pending') {this.state = 'fulfilled';this.value = value;this.onFulfilledCallbacks.forEach(fn => fn());}};const reject = (reason) => {if (this.state === 'pending') {this.state = 'rejected';this.reason = reason;this.onRejectedCallbacks.forEach(fn => fn());}};// 使用try-catch捕获执行器中的同步错误try {executor(resolve, reject);} catch (error) {reject(error);}}// then 方法then(onFulfilled, onRejected) {// 处理参数可选性onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;onRejected = typeof onRejected === 'function' ? onRejected : error => { throw error; };// 实现链式调用let promise2 = new MyPromise((resolve, reject) => {const handleCallback = (callback, value) => {setTimeout(() => {try {let x = callback(value);resolvePromise(promise2, x, resolve, reject);} catch (error) {reject(error);}});};if (this.state === 'fulfilled') {handleCallback(onFulfilled, this.value);} else if (this.state === 'rejected') {handleCallback(onRejected, this.reason);} else if (this.state === 'pending') {this.onFulfilledCallbacks.push(() => handleCallback(onFulfilled, this.value));this.onRejectedCallbacks.push(() => handleCallback(onRejected, this.reason));}});return promise2}catch(onRejected) {return this.then(null, onRejected);}finally(onFinally) {return this.then(value => MyPromise.resolve(onFinally()).then(() => value),reason => MyPromise.resolve(onFinally().then(() => { throw reason; }));}static resolve(value) {if (value instanceof MyPromise) return value;return new MyPromise(resolve => resolve(value));}static reject(reason) {return new Promise((resolve, reject) =>reject(reason));}static all(promises) {return new MyPromise((resolve, reject) => {const results = [];let remaining = promises.length;promises.forEach((promise, index) => {MyPromise.resolve(promise).then(value => {results[index] = value;remaining--;if (remaining == 0) {resolve(results);}},reason => reject(reason));});});}static race(promise) {return new MyPromise((resolve, reject) => {promise.forEach(promise => {MyPromise.resolve(promise).then(resolve, reject);});});}
}
// resolvePromise函数
// 处理循环引用
// used 确保thenable的then方法只调用一次
function resolvePromise(promise2, x, resolve, reject) {if (promise2 === x) {return reject(new TypeError('Chaining cycle detected for promise'));}// 如果x是promise,递归解包直到非promise值if (x instanceof MyPromise) {x.then(y => resolvePromise(promise2, y, resolve, reject), reject);return;}// 如果x是thenable对象,具有then的方法的对象或函数,调用其then方法if (x !== null && (typeof x === 'object' || typeof x === 'function')) {let used;try {let then = x.then;if (typeof then === 'function') {then.call(x,y => {if (used) return;used = true;resolvePromise(promise2, y, resolve, reject);},r => {if (used) return;used = true;reject(r);});} else {resolve(x);}} catch (error) {if (used) return;used = true;reject(error);}}else {resolve(x);}
}

逐步分析

定义属性。
回调队列用于存储 .then() 注册的异步回调,当状态改变时统一执行。
executor 是创建 Promise 时传入的函数(此时为形参)

constructor(executor) {// 状态:pending、fulfilled、rejectedthis.state = 'pending';this.value = undefined; // 成功时的值this.reason = undefined; // 失败时的原因this.onFulfilledCallbacks = []; // 成功时的回调队列this.onRejectedCallbacks = []; // 失败时的回调队列

只有在 pending 状态下才能改变状态(确保状态不可逆)。

const resolve = (value) => {if (this.state === 'pending') {this.state = 'fulfilled';this.value = value;// 执行所有通过 .then() 注册的成功回调(这些回调是在 pending 时注册的)。this.onFulfilledCallbacks.forEach(fn => fn()); }
};

reject 函数与 resolve 函数类似,区别在于该函数保存返回的是失败原因,并执行所有失败回调。

const reject = (reason) => {if (this.state === 'pending') {this.state = 'rejected';this.reason = reason;this.onRejectedCallbacks.forEach(fn => fn());}
};

executor(resolve, reject) 表示执行传入的执行器函数,并以 resolve, reject 为参数。

以 resolve, reject为参数时,这是两个函数参数,这两个函数用于改变 Promise 的状态,并且把 value 或 reason 保存起来,供.then().catch()调用。

try {executor(resolve, reject); 
} catch (error) {reject(error); // 如果 executor 内部出错,直接 reject 
}

.then 方法用来听通知:Promise什么时候成功 / 失败,成功做了什么 / 做什么失败了。所有Promise实例必须有 .then方法。只有表示异步操作结果的对象才需要.then

onFulfilled 默认是 透传值:value => value(值穿透)
onRejected 默认是 抛出错误:error => { throw error }(错误继续向下传)

// then 方法then(onFulfilled, onRejected) {// 处理参数可选性onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;onRejected = typeof onRejected === 'function' ? onRejected : error => { throw error; };

实现链式调用:返回 promise2。

        // 实现链式调用let promise2 = new MyPromise((resolve, reject) => {const handleCallback = (callback, value) => {setTimeout(() => {try {let x = callback(value);resolvePromise(promise2, x, resolve, reject);} catch (error) {reject(error);}});};if (this.state === 'fulfilled') {handleCallback(onFulfilled, this.value);} else if (this.state === 'rejected') {handleCallback(onRejected, this.reason);} else if (this.state === 'pending') {this.onFulfilledCallbacks.push(() => handleCallback(onFulfilled, this.value));this.onRejectedCallbacks.push(() => handleCallback(onRejected, this.reason));}});return promise2}

单独对传入的形参 executor 进行分析。
handleCallback 函数是一个内部辅助函数,用来统一处理回调执行。
这里的callback又是函数形参,以后放用户传给.then()的函数如 onFulfilledonRejected
value 中传上一个Promise的成功值或失败原因。

(resolve, reject) => {const handleCallback = (callback, value) => {// 异步执行setTimeout(() => {try {let x = callback(value);resolvePromise(promise2, x, resolve, reject);} catch (error) {reject(error);}});};

这里讲述一下resolvePromise的作用:根据 x 的类型决定如何设置 promise2 的状态。
如果 x 是普通值 → resolve(x)
如果 x 是 Promise → promise2 跟随它的状态

对于跟随状态的解释:
运动员 A(promise1)跑完 → 把接力棒交给 B
运动员 B(promise2)拿到棒 → 开始跑
B 的成绩取决于他自己的表现,而不是 A 的

如果 x 是 thenable → 调用它的 .then() 并等待
如果 x === promise2 → 循环引用,报错
如果 x 是对象且有 .then 方法 → 当作 thenable 处理

如果当前Promise已经成功,立即异步执行成功回调并传入成功值。
失败传原因balabalabala…

如果还没有执行,把这个回调函数放入等待队列,最开始创建的队列。

            if (this.state === 'fulfilled') {handleCallback(onFulfilled, this.value);} else if (this.state === 'rejected') {handleCallback(onRejected, this.reason);} else if (this.state === 'pending') {this.onFulfilledCallbacks.push(() => handleCallback(onFulfilled, this.value));this.onRejectedCallbacks.push(() => handleCallback(onRejected, this.reason));}});

每一个.then()返回的promise2都在等待前一个异步操作完成。

接下来实现catch函数,它只处理失败情况。
采取的措施是,一直传递失败。

    catch(onRejected) {return this.then(null, onRejected);}

然后实现finally函数,不管成功还是失败,都要执行它。成功传值,失败传错误。

    finally(onFinally) {return this.then(value => MyPromise.resolve(onFinally()).then(() => value),reason => MyPromise.resolve(onFinally().then(() => { throw reason; })));}

static resolve用来返回一个已成功的Promise

static resolve(value) {if (value instanceof MyPromise) return value;return new MyPromise(resolve => resolve(value));
}

static reject 用来创建一个已失败的Promise
static reject(reason) {
return new MyPromise((resolve, reject) => reject(reason));
}
等待所有 Promise 完成,如果都成功,返回结果数组;只要有一个失败,就立即失败。

static all(promises) {return new MyPromise((resolve, reject) => {const results = [];let remaining = promises.length;promises.forEach((promise, index) => {MyPromise.resolve(promise).then(value => {results[index] = value;remaining--;if (remaining == 0) {resolve(results);}},reason => reject(reason));});});
}

只要有一个 Promise 完成(成功或失败),就采用它的结果。

static race(promises) {return new MyPromise((resolve, reject) => {promises.forEach(promise => {MyPromise.resolve(promise).then(resolve, reject);});});
}

同一个类中,写了const resolve又写了static resolve,它们之间没有冲突。虽然名字都是 resolve,但它们存在于完全不同的作用域和上下文中,不会互相干扰。reject同理。

在race和all中,直接调用了static resolve(value);而reject部分使用的是当前实例的reject函数。


文章转载自:

http://kRZZ0RHv.dswtz.cn
http://YTkddEur.dswtz.cn
http://KDhwSF7v.dswtz.cn
http://jQ0cdL4g.dswtz.cn
http://TeHugykS.dswtz.cn
http://gHzOCEF8.dswtz.cn
http://Q3CDGwdv.dswtz.cn
http://ilQC3CmP.dswtz.cn
http://NwrnVFKt.dswtz.cn
http://CHCl3iFN.dswtz.cn
http://b4boPWwc.dswtz.cn
http://kXcb7eRo.dswtz.cn
http://13CD846p.dswtz.cn
http://fqXyfvr7.dswtz.cn
http://9s8jFN9p.dswtz.cn
http://sNDuytJG.dswtz.cn
http://h7XbRLDR.dswtz.cn
http://ThExKRYP.dswtz.cn
http://H80VhCIg.dswtz.cn
http://at1ZF17Q.dswtz.cn
http://9FlpdSJQ.dswtz.cn
http://afkC6TLP.dswtz.cn
http://QKHQzvYI.dswtz.cn
http://Ou8Tbc5q.dswtz.cn
http://0fIDKmSp.dswtz.cn
http://ifLZvYqy.dswtz.cn
http://eWqsa8Gm.dswtz.cn
http://ULV9hr3b.dswtz.cn
http://zk157SCj.dswtz.cn
http://CFJ5InUx.dswtz.cn
http://www.dtcms.com/a/372967.html

相关文章:

  • 第5篇 pytorch卸载方法与更换版本
  • 56.【.NET8 实战--孢子记账--从单体到微服务--转向微服务】--新增功能--实现手机邮箱找回密码
  • 月2期学习笔记
  • [新启航]新启航激光频率梳方案:击穿光学遮挡壁垒,以 2μm 精度实现 130mm 深孔 3D 轮廓测量
  • 51单片机驱动数码管
  • 51单片机基础结构及编程要点
  • Git Bash 别名
  • 福彩双色球第2025104期篮球号码分析
  • C++模板进阶:从基础到高级实战技巧
  • 力扣每日一题p1317 将整数转换…… 题解
  • 量子密码:后量子的加密
  • 【 ​​SQL注入漏洞靶场】第二关文件读写
  • wpf .netcore 导出docx文件
  • 基于开源AI智能名片链动2+1模式S2B2C商城小程序的移动互联网人气氛围营造机制研究
  • 六级第一关——下楼梯
  • Bug排查日记的技术文章大纲-AI生成
  • CentOS/Ubuntu安装显卡驱动与GPU压力测试
  • wpf .netcore 导出pdf文件
  • 6个步骤实现Postman接口压力测试
  • Linux-expect脚本编程
  • Dart 聊天后端开发(MongoDB + WebSocket)
  • Linux初始——自动化构建
  • Linux之GDB调试
  • 通俗理解 LSTM 的三门机制:从剧情记忆到科学原理
  • MyBatis-Plus中 IService 与 ServiceImpl等内容的深入思考理解
  • Android使用ReactiveNetwork监听网络连通性
  • 大学信息查询平台:一个现代化的React教育项目
  • 基于 GitHub Actions 的零成本自动化部署:把 Vite/Vue3 项目一键发布到 GitHub Pages 的完整实战
  • 制造企业如何实现ERP/OA/CRM/WMS等多系统贯通
  • 2025年5月架构设计师案例分析真题回顾,附参考答案、解析及所涉知识点(五)