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

Promise手写实现

回忆

         回忆一下Promise的基本知识点,通常有三个状态:pending、fulfilled、rejected。它有一个then方法,用于处理异步操作的结果,还有catch方法用于处理错误。另外,Promise还有resolve和reject方法,以及静态方法如all、race、resolve、reject等。

ES5版本

        在ES5中,没有class语法,所以应该使用构造函数和原型方法。Promise的构造函数应该接收一个executor函数,这个函数有两个参数:resolve和reject。这两个函数用于改变Promise的状态。接下来,状态一旦改变就不能再改变,所以需要设置状态变量,比如this.state,初始为pending,当调用resolve时变为fulfilled,reject时变为rejected。同时,需要保存结果值,比如this.value或this.reason。

        然后,then方法需要处理onFulfilled和onRejected回调。这些回调应该被推入一个队列,以便在状态改变时执行。需要注意的是,then方法返回一个新的Promise,以便支持链式调用。还需要处理异步执行的问题,确保回调是在下一个事件循环中执行,通常使用setTimeout来实现。

        另外,要处理then方法中的返回值。如果回调返回一个Promise,则新的Promise的状态和结果取决于这个返回的Promise。如果返回的是普通值,则新的Promise被resolve为这个值。如果抛出异常,则新的Promise被reject。还需要实现catch方法,它实际上是then方法的语法糖,即then(null, onRejected)。

        静态方法方面,Promise.resolve和Promise.reject可以直接返回一个新的Promise,状态分别为fulfilled或rejected,并携带相应的值。Promise.all方法接收一个可迭代对象(如数组),返回一个新的Promise,当所有Promise都fulfilled时,新的Promise被resolve为包含各结果的数组;如果有任何一个被reject,则立即reject,并携带第一个reject的原因。

        Promise.race方法则是返回第一个改变状态的Promise的结果,无论是fulfilled还是rejected。在实现过程中,需要注意处理this绑定问题,确保在回调中正确引用Promise实例。另外,要处理循环引用和错误处理,比如executor中的异常需要被捕获并reject。要考虑Promise的延迟执行特性,即executor函数是同步执行的,但then的回调是异步的。

<script>function MyPromise(executor) {var self = this;self.state = 'pending'; // 初始状态为 pendingself.value = undefined; // 成功时传递的值self.reason = undefined; // 失败时传递的原因self.onFulfilledCallbacks = []; // 存储成功回调队列self.onRejectedCallbacks = [];   // 存储失败回调队列/*** 将 Promise 状态从 pending 转换为 fulfilled,并执行所有成功回调。* @param {*} value - 成功时传入的值*/function resolve(value) {if (self.state !== 'pending') return;self.state = 'fulfilled';self.value = value;self.onFulfilledCallbacks.forEach(function (callback) {callback(value);});}/*** 将 Promise 状态从 pending 转换为 rejected,并执行所有失败回调。* @param {*} reason - 失败时传入的原因*/function reject(reason) {if (self.state !== 'pending') return;self.state = 'rejected';self.reason = reason;self.onRejectedCallbacks.forEach(function (callback) {callback(reason);});}try {executor(resolve, reject); // 启动执行器} catch (e) {reject(e); // 捕获异常并调用 reject}}/*** 实现 .then 方法,用于注册成功和失败的回调函数。* @param {Function} onFulfilled - 当前 Promise 成功后的回调函数* @param {Function} onRejected - 当前 Promise 失败后的回调函数* @returns {MyPromise} 返回一个新的 MyPromise 实例以支持链式调用*/MyPromise.prototype.then = function (onFulfilled, onRejected) {var self = this;// 创建新的 Promise 对象用于链式调用var promise2 = new MyPromise(function (resolve, reject) {if (self.state === 'fulfilled') {try {var x = onFulfilled(self.value);resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e);}} else if (self.state === 'rejected') {try {var x = onRejected(self.reason);resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e);}} else {// 异步情况:将回调加入等待队列中self.onFulfilledCallbacks.push(function () {try {var x = onFulfilled(self.value);resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e);}});self.onRejectedCallbacks.push(function () {try {var x = onRejected(self.reason);resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e);}});}});return promise2;};/*** 实现 .catch 方法,是 .then(null, onRejected) 的语法糖。* @param {Function} onRejected - 错误处理回调函数* @returns {MyPromise} 返回一个新的 MyPromise 实例*/MyPromise.prototype.catch = function (onRejected) {return this.then(null, onRejected);};/*** @param {MyPromise} promise - 新创建的 Promise 实例* @param {*} x - 上一个 then 回调返回的结果* @param {Function} resolve - 新 Promise 的 resolve 函数* @param {Function} reject - 新 Promise 的 reject 函数*/function resolvePromise(promise, x, resolve, reject) {var called = false;// 防止循环引用导致死锁if (promise === x) {return reject(new TypeError('Chaining cycle'));}if (x instanceof MyPromise) {// 如果 x 是一个 Promise,则递归解析其结果x.then(function (value) {resolvePromise(promise, value, resolve, reject);}, reject);} else if ((typeof x === 'object' && x !== null) || typeof x === 'function') {try {var then = x.then;if (typeof then === 'function') {// 如果 x 具有 then 方法,则将其视为 thenable 并尝试转换为 Promisethen.call(x,function (y) {if (called) return;called = true;resolvePromise(promise, y, resolve, reject);},function (r) {if (called) return;called = true;reject(r);});} else {resolve(x); // 不是函数则直接 resolve 值}} catch (e) {if (called) return;reject(e); // 出错则拒绝新 Promise}} else {resolve(x); // 基本类型值直接 resolve}}/*** 静态方法:创建一个已成功的 Promise。* @param {*} value - 成功的值* @returns {MyPromise} 已完成状态的 Promise*/MyPromise.resolve = function (value) {return new MyPromise(function (resolve) {resolve(value);});};/*** 静态方法:创建一个已失败的 Promise。* @param {*} reason - 失败原因* @returns {MyPromise} 已拒绝状态的 Promise*/MyPromise.reject = function (reason) {return new MyPromise(function (_, reject) {reject(reason);});};/*** 静态方法:等待所有 Promise 完成,若任一失败则立即失败。* @param {Array} promises - 包含多个 Promise 或普通值的数组* @returns {MyPromise} 当所有都完成时成功,否则第一个失败即失败*/MyPromise.all = function (promises) {return new MyPromise(function (resolve, reject) {var values = [];var completedCount = 0;var len = promises.length;if (len === 0) return resolve([]);/*** 处理某个 Promise 成功的情况,记录对应索引位置的值。* @param {number} index - 数组中的索引* @param {*} value - 成功的值*/function processFulfilled(index, value) {values[index] = value;if (++completedCount === len) resolve(values);}for (var i = 0; i < len; i++) {(function (i) {if (promises[i] instanceof MyPromise) {promises[i].then(function (value) {processFulfilled(i, value);}, reject);} else {processFulfilled(i, promises[i]);}})(i);}});};/*** 静态方法:只要有一个 Promise 完成就立刻完成。* @param {Array} promises - 包含多个 Promise 或普通值的数组* @returns {MyPromise} 第一个完成的 Promise 决定整体结果*/MyPromise.race = function (promises) {return new MyPromise(function (resolve, reject) {for (var i = 0; i < promises.length; i++) {promises[i].then(resolve, reject);}});};// 基础功能测试var p1 = new MyPromise(function (resolve, reject) {setTimeout(function () {resolve('成功');}, 100);});p1.then(function (value) {console.log(value); // 输出:成功return '链式成功';}).then(function (value) {console.log(value); // 输出:链式成功});// 错误测试var p2 = new MyPromise(function (resolve, reject) {reject('失败');});p2.catch(function (reason) {console.log(reason); // 输出:失败});// 静态方法测试MyPromise.resolve('静态成功').then(function (value) {console.log(value); // 输出:静态成功});MyPromise.reject('静态失败').catch(function (reason) {console.log(reason); // 输出:静态失败});// all测试var p3 = MyPromise.resolve(1);var p4 = new MyPromise(function (resolve) {setTimeout(function () {resolve(2);}, 50);});var p5 = MyPromise.reject('all失败');MyPromise.all([p3, p4]).then(function (values) {console.log(values); // 输出:[1, 2]});MyPromise.all([p3, p5]).catch(function (reason) {console.log(reason); // 输出:all失败});// race测试var p6 = new MyPromise(function (resolve) {setTimeout(function () {resolve('race成功');}, 100);});var p7 = new MyPromise(function (resolve, reject) {setTimeout(function () {reject('race失败');}, 50);});MyPromise.race([p6, p7]).catch(function (reason) {console.log(reason); // 输出:race失败});
</script>

要点:

  1. 状态管理:使用pending/fulfilled/rejected三种状态,状态变更不可逆
  2. 异步执行:通过setTimeout实现回调的异步执行
  3. 链式调用:then返回新Promise实现链式调用
  4. 错误捕获:try/catch包裹回调执行,自动捕获同步和异步错误
  5. 值穿透:自动处理非Promise返回值
  6. 静态方法
    • resolve/reject:创建对应状态的Promise
    • all:等待所有Promise完成,返回结果数组
    • race:返回最快完成的Promise结果

ES6版本

        这里需要定义一个Promise类,构造函数接受一个executor函数,这个函数有两个参数:resolve和reject。在executor内部,调用resolve会将状态改为fulfilled,并保存value;调用reject会将状态改为rejected,并保存reason。

        pending状态改变一次,所以需要设置一个标志确保只能调用一次resolve或reject。然后,then方法需要返回一个新的Promise,以便链式调用。在then方法中,需要处理onFulfilled和onRejected回调。如果主Promise的状态已经是fulfilled或rejected,直接执行对应的回调。如果是pending状态,需要将回调存入队列,等状态改变后再执行。

        还需要处理回调函数的返回值。如果回调返回一个Promise,新的Promise的状态和值由这个返回的Promise决定。如果返回其他值,新的Promise会以该值为resolve。如果抛出错误,则reject。

        还要考虑Promise的resolve方法,如果传入的是一个Promise,需要展开它,直到得到一个非Promise的值。还需要处理错误捕获,比如executor中的异常,应该被捕获并调用reject。

        首先定义Promise类,构造函数中处理executor,保存状态和结果。然后实现then方法,处理回调和状态传递。还需要实现catch方法,它实际上是then(null, onRejected)的语法糖。还需要处理Promise的静态方法,比如resolve、reject、all、race等。

<script>const PENDING = 'pending';const FULFILLED = 'fulfilled';const REJECTED = 'rejected';class MyPromise {/*** 构造函数,初始化 Promise 实例* @param {Function} executor - 执行器函数,接收 resolve 和 reject 两个参数*/constructor(executor) {this.state = PENDING; // 当前状态this.value = undefined; // 成功时的值this.reason = undefined; // 失败时的原因this.onFulfilledCallbacks = []; // 存储成功回调函数队列this.onRejectedCallbacks = []; // 存储失败回调函数队列/*** 将 Promise 状态从 pending 转换为 fulfilled,并执行所有成功回调* @param {*} value - 成功传递的值*/const resolve = (value) => {if (this.state !== PENDING) return;this.state = FULFILLED;this.value = value;this.onFulfilledCallbacks.forEach(fn => fn());};/*** 将 Promise 状态从 pending 转换为 rejected,并执行所有失败回调* @param {*} reason - 失败传递的原因*/const reject = (reason) => {if (this.state !== PENDING) return;this.state = REJECTED;this.reason = reason;this.onRejectedCallbacks.forEach(fn => fn());};try {executor(resolve, reject);} catch (error) {reject(error);}}/*** 注册成功和失败的回调函数* @param {Function} onFulfilled - 成功时的回调函数* @param {Function} onRejected - 失败时的回调函数* @returns {MyPromise} 返回一个新的 Promise 实例以支持链式调用*/then(onFulfilled, onRejected) {// 如果不是函数,则使用默认处理函数onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;onRejected = typeof onRejected === 'function'? onRejected: reason => { throw reason; };const promise2 = new MyPromise((resolve, reject) => {/*** 成功状态下的处理函数*/const fulfilledHandler = () => {queueMicrotask(() => {try {const x = onFulfilled(this.value);resolvePromise(promise2, x, resolve, reject);} catch (error) {reject(error);}});};/*** 失败状态下的处理函数*/const rejectedHandler = () => {queueMicrotask(() => {try {const x = onRejected(this.reason);resolvePromise(promise2, x, resolve, reject);} catch (error) {reject(error);}});};if (this.state === FULFILLED) {fulfilledHandler();} else if (this.state === REJECTED) {rejectedHandler();} else {this.onFulfilledCallbacks.push(fulfilledHandler);this.onRejectedCallbacks.push(rejectedHandler);}});return promise2;}/*** 注册失败的回调函数,是 then(null, onRejected) 的语法糖* @param {Function} onRejected - 失败时的回调函数* @returns {MyPromise} 返回一个新的 Promise 实例*/catch(onRejected) {return this.then(null, onRejected);}/*** 注册无论成功或失败都会执行的回调函数* @param {Function} onFinally - 最终执行的回调函数* @returns {MyPromise} 返回一个新的 Promise 实例*/finally(onFinally) {return this.then(value => new MyPromise(resolve => {resolve(value);}),reason => new MyPromise((_, reject) => {reject(reason);}));}}/*** 解析并处理 then 方法返回值 x,决定 promise2 的状态* @param {MyPromise} promise - 当前要解析的 Promise 实例* @param {*} x - then 方法返回的值* @param {Function} resolve - promise2 的 resolve 函数* @param {Function} reject - promise2 的 reject 函数*/function resolvePromise(promise, x, resolve, reject) {if (promise === x) {reject(new TypeError('Chaining cycle detected'));return;}if (x instanceof MyPromise) {x.then(resolve, reject);} else if (x && (typeof x === 'object' || typeof x === 'function')) {let called = false;try {const then = x.then;if (typeof then === 'function') {then.call(x,y => {if (called) return;called = true;resolvePromise(promise, y, resolve, reject);},r => {if (called) return;called = true;reject(r);});} else {resolve(x);}} catch (error) {if (called) return;reject(error);}} else {resolve(x);}}/*** 静态方法:创建一个已成功完成的 Promise 实例* @param {*} value - 成功传递的值* @returns {MyPromise} 返回一个成功的 Promise 实例*/MyPromise.resolve = function (value) {return new MyPromise(resolve => resolve(value));};/*** 静态方法:创建一个已失败的 Promise 实例* @param {*} reason - 失败传递的原因* @returns {MyPromise} 返回一个失败的 Promise 实例*/MyPromise.reject = function (reason) {return new MyPromise((_, reject) => reject(reason));};/*** 静态方法:等待所有 Promise 完成,任一失败则整体失败* @param {Array} promises - Promise 数组* @returns {MyPromise} 返回一个包含所有结果的 Promise 实例*/MyPromise.all = function (promises) {return new MyPromise((resolve, reject) => {const values = [];let completed = 0;if (promises.length === 0) {resolve(values);return;}promises.forEach((promise, index) => {MyPromise.resolve(promise).then(value => {values[index] = value;completed++;if (completed === promises.length) resolve(values);},reason => reject(reason));});});};/*** 静态方法:返回最先完成的 Promise 结果* @param {Array} promises - Promise 数组* @returns {MyPromise} 返回第一个完成的 Promise 实例*/MyPromise.race = function (promises) {return new MyPromise((resolve, reject) => {promises.forEach(promise => {MyPromise.resolve(promise).then(resolve, reject);});});};// 测试用例const promise = new MyPromise((resolve, reject) => {setTimeout(() => resolve('Success'), 1000);});promise.then(value => {console.log(value); // 1秒后输出 'Success'return 'Next';}).then(value => {console.log(value); // 输出 'Next'});// 链式调用测试new MyPromise(resolve => resolve(1)).then(x => x * 2).then(x => x + 3).then(x => console.log(x)); // 输出 5// 错误传递测试new MyPromise((_, reject) => reject('Error')).catch(err => console.log(`Caught: ${err}`)); // 输出 'Caught: Error'
</script>

关键点

  1. 状态管理:严格遵循pending → fulfilled/rejected的不可变状态转换
  2. 异步执行:使用queueMicrotask实现微任务队列
  3. 链式调用then返回新Promise实现链式调用
  4. 值穿透:自动处理非函数回调
  5. 错误捕获:自动捕获回调中的异常
  6. 值传递规则
    • 普通值直接传递
    • Promise对象展开传递
    • 防止循环引用
  7. 静态方法:实现resolve/reject/all/race方法
  8. finally语义:保持原始Promise状态不变

完结。。。

http://www.dtcms.com/a/541228.html

相关文章:

  • keep-alive | vue 中的 keep-alive 和 http中 的 Connection: keep-alive 共同点 和 区别
  • Win+VsCode关于C++项目改造成http服务
  • redis的备份和恢复
  • 北京最大网站建设公司排名做网站的商标是哪类
  • 神经网络初探
  • 鸿蒙Flutter三方库适配指南-04.使用MacOS搭建开发环境
  • 网站建设的风险管理网站开发用了什么平台
  • 鸿蒙应用的启动流程的过程
  • springboot Admin 服务端 客户端配置
  • PHP 中的动态函数调用
  • 设计类参考网站推荐简单企业网站建设
  • 网站优化排名价格网站建设应对客户问题的话术
  • AI IN ALL峰会|百度阿里揭秘智能营销与出海的AI实战
  • 网络安全相关知识
  • wordpress软件站模板外贸采购网官网
  • Apache Flink Keyed State 详解之一
  • 机器学习、深度学习、信号处理领域常用符号速查表
  • Linux小课堂: Squid代理缓存服务器部署与访问控制实战指南
  • 开发Electron程序
  • 中英文网站建站关键词优化ppt
  • 渭南建设用地规划查询网站视觉设计网站建设
  • linux定时任务和发送邮件
  • 零基础新手小白快速了解掌握服务集群与自动化运维(十五)Redis模块-Redis集群理论、手动部署
  • 51zwd一起做网站网站的中英文切换代码
  • 电商领域异地组网需求与解决方案
  • 英语学习 第一天 重难点
  • devc++新建单个文件和新建单个项目
  • 收集域名信息-whois查询
  • Android实战进阶 - CircleIndicator指示器样式定制
  • SQL-leetcode—3475. DNA 模式识别