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

手写Promise源码的实现思路

Promise的使用:

let promise = new Promise((resolve, reject) => {resolve("OK");// reject("Error");
});console.log(promise);promise.then(value => {console.log("success");
}, error => {console.log("fail");
});
  1. 定义构造函数中的两个基本属性PromiseStatePromiseResult

    function Promise() {this.PromiseState = "pending";this.PromiseResult = null;
    }
    
  2. 由于实例对象中传递的参数是一个执行器函数,并且会立即执行这个函数。

    function Promise(executor) {this.PromiseState = "pending";this.PromiseResult = null;executor();
    }
    
  3. 该执行器函数中有两个函数参数,调用任意一个函数会改变promise的状态和结果值,且状态只能改变一次。

    function Promise(executor) {this.PromiseState = "pending";this.PromiseResult = null;// 防止this指向windowconst self = this;function resolve(value) {if(self.PromiseState !== "pending") return;self.PromiseState = "fulfilled";self.PromiseResult = value;}function reject(reason) {if(self.PromiseState !== "pending") return;self.PromiseState = "rejected";self.PromiseResult = reason;}// 参数为一个函数且立即执行,该函数需要两个函数参数改变promise的状态和结果值executor(resolve, reject);
    }
    
  4. 还有一种情况:promise实例执行结果为抛出异常,需要让其状态为失败。

    function Promise(executor) {// ...// 参数为一个函数且立即执行,该函数需要两个函数参数改变promise的状态和结果值;抛出异常时状态为失败try {executor(resolve, reject);} catch (error) {reject(error);}
    }
    
  5. 在对象原型上添加then方法。

    Promise.prototype.then = function(onResolved, onRejected) {if(this.PromiseState === "fulfilled") {onResolved();}if(this.PromiseState === "rejected") {onRejected();}
    }
    
  6. executor的执行内容是异步的,应该等到异步执行后改变了状态才能执行then中的回调函数,异步执行前状态还是为pending

    let promise = new Promise((resolve, reject) => {setTimeout(()=> {resolve("OK");}, 1000);
    });
    
    function Promise(executor) {// ...this.callback = null;// 防止this指向windowconst self = this;function resolve(value) {if(self.PromiseState !== "pending") return;self.PromiseState = "fulfilled";self.PromiseResult = value;if(self.callback.onResolved) {self.callback.onResolved();}}function reject(reason) {if(self.PromiseState !== "pending") return;self.PromiseState = "rejected";self.PromiseResult = reason;if(self.callback.onRejected) {self.callback.onRejected();}}// ...
    }// then方法
    Promise.prototype.then = function(onResolved, onRejected) {// ...if(this.PromiseState === "pending") {// 此时还未改变promise的状态,回调函数无法立即执行,只能先保存下来this.callback = {onResolved,onRejected};}
    }
    
  7. 当一个Promise实例执行了多个then方法时,两个then里的方法都会执行。

    let promise = new Promise((resolve, reject) => {resolve("OK");
    });promise.then(value => {console.log("success");
    }, error => {console.log("fail");
    });promise.then(value => {console.log("success2");
    }, error => {console.log("fail2");
    });
    // success success2
    
    function Promise(executor) {// ...this.callback = null;// 防止this指向windowconst self = this;function resolve(value) {if(self.PromiseState !== "pending") return;self.PromiseState = "fulfilled";self.PromiseResult = value;self.callbacks.forEach(item => {item.onResolved();});}function reject(reason) {if(self.PromiseState !== "pending") return;self.PromiseState = "rejected";self.PromiseResult = reason;self.callbacks.forEach(item => {item.onRejected();});}// ...
    }// then方法
    Promise.prototype.then = function(onResolved, onRejected) {// ...if(this.PromiseState === "pending") {// 此时还未改变promise的状态,回调函数无法立即执行,只能先保存下来this.callbacks.push({onResolved,onRejected});}
    }
    
  8. then方法返回的也是一个Promise实例,这个实例的状态由执行的回调函数的结果来决定,如果回调函数的执行内容是非Promise实例,则都为成功状态;如果是Promise实例,状态根据这个实例的状态来定。

    • executor执行内容为同步时:

      Promise.prototype.then = function(onResolved, onRejected) {const self = this;return new Promise((resolve, reject) => {if(self.PromiseState === "fulfilled") {// 拿到回调函数的返回值// Promise实例:根据其结果状态决定then执行后该实例的状态;非Promise实例:状态都为成功const result = onResolved(self.PromiseResult);if(result instanceof Promise) {// 既然是一个Promise实例,就能根据该实例的执行内容确定状态result.then(v => {resolve(v);}, r => {reject(r);});} else {resolve(result);}}if(self.PromiseState === "rejected") {// 同上const result = onRejected(self.PromiseResult);if(result instanceof Promise) {result.then(v => {resolve(v);}, r => {reject(r);});} else {resolve(result);}}}// ...})
      }
      
    • executor执行内容为异步时:

      Promise.prototype.then = function(onResolved, onRejected) {const self = this;return new Promise((resolve, reject) => {// ...if(self.PromiseState === "pending") {// 此时还未改变promise的状态,回调函数无法立即执行,只能先保存下来self.callbacks.push({onResolved: function() {// 同上const result = onResolved(self.PromiseResult);if(result instanceof Promise) {result.then(v => {resolve(v);}, r => {reject(r);});} else {resolve(result);}},onRejected: function() {// 同上const result = onRejected(self.PromiseResult);if(result instanceof Promise) {result.then(v => {resolve(v);}, r => {reject(r);});} else {resolve(result);}}});}})
      }
      
  9. 封装then方法中出现的重复代码,并处理

    Promise.prototype.then = function(onResolved, onRejected) {const self = this;return new Promise((resolve, reject) => {// 封装函数:根据结果改变状态function callback(fn) {try {// 拿到回调函数的返回值// Promise实例:根据其结果状态决定then执行后该实例的状态;非Promise实例:状态都为成功let result = fn(self.PromiseResult);if(result instanceof Promise) {// 既然是一个Promise实例,就能根据该实例的执行内容确定状态result.then(v => {resolve(v);}, r => {reject(r);});} else {resolve(result);}} catch (error) {reject(error);}}if(self.PromiseState === "fulfilled") {callback(onResolved);}if(self.PromiseState === "rejected") {callback(onRejected);}if(self.PromiseState === "pending") {// 此时还未改变promise的状态,回调函数无法立即执行,只能先保存下来self.callbacks.push({onResolved: function() {callback(onResolved);},onRejected: function() {callback(onRejected);}});}})
    }
    
  10. 添加catch方法并实现异常穿透,同时实现then只传递一个参数和不传递参数的情况。

    // 使用
    promise.then(value => {return new Promise((resolve, reject) => {reject("111 error")})
    }).then((value) => {console.log(222)
    }).catch(err => {console.log("err-------------")console.log(err)
    });
    
    // then方法
    Promise.prototype.then = function(onResolved, onRejected) {const self = this;// 不传第二个函数时,默认函数为一个抛出异常操作if(typeof onRejected !== "function") {onRejected = reason => {throw reason;}}// 不传第一个函数时,默认将实例结果值返回,可以实现成功时的值传递if(typeof onResolved !== "function") {onResolved = value => value;}return new Promise((resolve, reject) => {// ...})
    }// catch方法
    Promise.prototype.catch = function(onRejected) {return this.then(undefined, onRejected);
    }
    
  11. 添加Promise.resolvePromisereject方法。

    // resolve方法:根据传入参数的类型决定结果的状态
    Promise.resolve = function(value) {return new Promise((resolve, reject) => {if(value instanceof Promise) {// 既然是一个Promise实例,就能根据该实例的执行内容确定状态value.then(v => {resolve(v);}, r => {reject(r);});} else {resolve(value);}})
    }// reject方法:无论传入的参数是什么类型,结果都是失败状态
    Promise.reject = function(reason) {return new Promise((resolve, reject) => {reject(reason);})
    }
    
  12. 添加Promise.all方法:所有实例都成功则为成功,结果值为所有实例结果值组成的数组;有一个失败,则为失败,结果值为失败的实例的结果值。

    Promise.all = function(promises) {return new Promise((resolve, reject) => {let count = 0,resultArr = [];promises.forEach((item, index) => {item.then(v => {count++;// 按实例的索引值存储其对应结果resultArr[index] = item.PromiseResult;// 全部都为成功时为成功if(count === promises.length) {resolve(resultArr);}}, r => {reject(r);});});})
    }
    
  13. 添加Promise.race方法:实例中谁先改变状态,返回的状态和结果值就为该实例的状态和结果值。

    Promise.race = function(promises) {return new Promise((resolve, reject) => {promises.forEach(item => {item.then(v => {resolve(v);}, r => {reject(r);});});})
    }
    
  14. then方法是一个异步任务。

    function Promise(executor) {// ...// 防止this指向windowconst self = this;function resolve(value) {// ...setTimeout(() => {self.callbacks.forEach(item => {item.onResolved();});});}function reject(reason) {// ...setTimeout(() => {self.callbacks.forEach(item => {item.onRejected();});});}// 参数为一个函数且立即执行,该函数需要两个函数参数改变promise的状态和结果值;抛出异常时状态为失败try {executor(resolve, reject);} catch (error) {reject(error);}
    }// then方法
    Promise.prototype.then = function(onResolved, onRejected) {// ...return new Promise((resolve, reject) => {// ...if(self.PromiseState === "fulfilled") {setTimeout(() => {callback(onResolved);});}if(self.PromiseState === "rejected") {setTimeout(() => {callback(onRejected);});}// ...})
    }
    

调整一下代码结构,整个promise.js源码如下:

function Promise(executor) {this.PromiseState = "pending";this.PromiseResult = null;this.callbacks = [];// 防止this指向windowconst self = this;function resolve(value) {if(self.PromiseState !== "pending") return;self.PromiseState = "fulfilled";self.PromiseResult = value;setTimeout(() => {self.callbacks.forEach(item => {item.onResolved();});});}function reject(reason) {if(self.PromiseState !== "pending") return;self.PromiseState = "rejected";self.PromiseResult = reason;setTimeout(() => {self.callbacks.forEach(item => {item.onRejected();});});}// 参数为一个函数且立即执行,该函数需要两个函数参数改变promise的状态和结果值;抛出异常时状态为失败try {executor(resolve, reject);} catch (error) {reject(error);}
}// then方法
Promise.prototype.then = function(onResolved, onRejected) {// 不传第一个函数时,默认将实例结果值返回,可以实现成功时的值传递if(typeof onResolved !== "function") {onResolved = value => value;}// 不传第二个函数时,默认函数为一个抛出异常操作if(typeof onRejected !== "function") {onRejected = reason => {throw reason;}}const self = this;return new Promise((resolve, reject) => {// 封装函数:根据结果改变状态function callback(fn) {try {// 拿到回调函数的返回值// Promise实例:根据其结果状态决定then执行后该实例的状态;非Promise实例:状态都为成功let result = fn(self.PromiseResult);if(result instanceof Promise) {// 既然是一个Promise实例,就能根据该实例的执行内容确定状态result.then(v => {resolve(v);}, r => {reject(r);});} else {resolve(result);}} catch (error) {reject(error);}}if(self.PromiseState === "pending") {// 此时还未改变promise的状态,回调函数无法立即执行,只能先保存下来self.callbacks.push({onResolved: function() {callback(onResolved);},onRejected: function() {callback(onRejected);}});} else if(self.PromiseState === "fulfilled") {setTimeout(() => {callback(onResolved);});} else if(self.PromiseState === "rejected") {setTimeout(() => {callback(onRejected);});}})
}// catch方法
Promise.prototype.catch = function(onRejected) {return this.then(undefined, onRejected);
}// resolve方法:根据传入参数的类型决定结果的状态
Promise.resolve = function(value) {return new Promise((resolve, reject) => {if(value instanceof Promise) {// 既然是一个Promise实例,就能根据该实例的执行内容确定状态value.then(v => {resolve(v);}, r => {reject(r);});} else {resolve(value);}})
}// reject方法:无论传入的参数是什么类型,结果都是失败状态
Promise.reject = function(reason) {return new Promise((resolve, reject) => {reject(reason);})
}// all方法
Promise.all = function(promises) {return new Promise((resolve, reject) => {let count = 0,resultArr = [];promises.forEach((item, index) => {item.then(v => {count++;// 按实例的索引值存储其对应结果resultArr[index] = item.PromiseResult;// 全部都为成功时为成功if(count === promises.length) {resolve(resultArr);}}, r => {reject(r);});});})
}// race方法
Promise.race = function(promises) {return new Promise((resolve, reject) => {promises.forEach(item => {item.then(v => {resolve(v);}, r => {reject(r);});});})
}

相关文章:

手写Promise源码的实现思路

Promise的使用: let promise new Promise((resolve, reject) > {resolve("OK");// reject("Error"); });console.log(promise);promise.then(value > {console.log("success"); }, error > {console.log("fail"…...

【数据结构】-关于树的概念和性质你了解多少??

作者:小树苗渴望变成参天大树 作者宣言:认真写好每一篇博客 作者gitee:gitee 如 果 你 喜 欢 作 者 的 文 章 ,就 给 作 者 点 点 关 注 吧! 树前言一、树概念及结构1.1树的概念1.2 树的相关概念1.3 树的表示1.4树在实际中的运用…...

【前端之旅】NPM必知必会

一名软件工程专业学生的前端之旅,记录自己对三件套(HTML、CSS、JavaScript)、Jquery、Ajax、Axios、Bootstrap、Node.js、Vue、小程序开发(UniApp)以及各种UI组件库、前端框架的学习。 【前端之旅】Web基础与开发工具 【前端之旅】手把手教你安装VS Code并附上超实用插件…...

Android SQLite使用事务来确保所有语句都以原子方式执行及保证数据完整性一次执行多条语句示例

execSQL 不支持用分号分隔一次执行多个 SQL 语句,虽然理论上可以实现。但是,并不建议这样做,因为这可能会导致潜在的 SQL 注入漏洞。相反,建议使用 execSQL 或 rawQuery 分别执行每个语句。 在下面的代码块中,我们正在…...

nodejs+vue校园超市小卖部零食在线购物商城系统

21世纪的今天,随着社会的不断发展与进步,人们对于信息科学化的认识,已由低层次向高层次发展,由原来的感性认识向理性认识提高,管理工作的重要性已逐渐被人们所认识,科学化的管理,使信息存储达到…...

Karl Guttag:论相机对焦技术在AR/VR中的沿用

近期,AR/VR光学专家Karl Guttag介绍了两家在CES 2023展出光学传感技术的公司:poLight和CML(剑桥机电一体化)。​同时介绍两家公司的原因,是因为他们提供了实现AR/VR“光学微动”(Optics Micromovement&…...

ECL@SS学习笔记(3)-概念数据模型

ECLSS 是产品,服务的分类和描述系统。本文介绍其内部的数据模型。ECLSS的作用ECLSS 标准的目标是为了实现工业界数据交换的标准化。这个标准主要作用是产品的分类和描述。分类为了有效地物料管理,供应链管理和电子商务,需要对物料进行分类和编…...

206. 反转链表

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。 示例 1: 输入:head [1,2,3,4,5] 输出:[5,4,3,2,1] 示例 2: 输入:head [1,2] 输出:[2,1] 示例 3: 输…...

文心一言 vs GPT-4 —— 全面横向比较

文心一言 vs GPT-4 —— 全面横向比较 3月15日凌晨,OpenAI发布“迄今为止功能最强大的模型”——GPT-4。我第一时间为大家奉上了体验报告《OpenAI 发布GPT-4——全网抢先体验》。 时隔一日,3月16日下午百度发布大语言模型——文心一言。发布会上&#…...

rancher2.6进阶之kubectl安装

rancher2.6进阶之kubectl安装 1.安装kubectl客户端 1.1.1.使用命令行下载安装包: curl -LO https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl Note: 可指定下载版本, 将 ( c u r l − L − s h t t p s : / / d l . k …...

图像基本变换

缩放与裁剪裁剪图像的裁剪,是指将图像的某个区域切割出来。一些常见的应用场景包括:* 感兴趣区域提取* 去除无用信息* 图像增强* 纠偏:去除不规则部分,将图像变得更加整齐事实上,图像裁剪的裁剪通常就是一个numpy矩阵切…...

基于文心一言的底层视觉理解,百度网盘把「猫」换成了「黄色的猫」

随着移动互联网的一路狂飙,手机已经成为人们的新器官。出门不带钥匙可以,不带手机却是万万不可以的。而手机上,小小的摄像头也越来越成为各位「vlogger」的口袋魔方。每天有超过数亿的照片和视频被上传到百度网盘中,这些照片和视频…...

安卓开发的环境配置教程

文章目录事先准备:下载 JDK、Gradle下载安装 Android Studio下载安装 Android SDK下载安装 ADB笔者的环境: Java 17.0.1 Gradle 8.0.1 Android Studio Electric Eel | 2022.1.1 Patch 1 Windows 10 教育版 64位 事先准备:下载 JDK、Gradl…...

【Spring Cloud Alibaba】Spring Cloud Alibaba 搭建教程

文章目录教程适用版本一、简介主要功能组件开源地址二、开始搭建1.项目搭建与依赖管理2.服务注册与发现(Nacos安装)3.创建服务提供者4.创建服务消费者5.创建服务消费者(Feign)6.添加熔断机制(Sentinel)7.Sentinel熔断器仪表盘监控…...

关于自动机器学习flaml训练时的一些报错

一、版本背景flaml 1.1.3sciket-learn 0.23.0二、一路报错2.1、SyntaxError: future feature annotations is not definedTraceback (most recent call last):File "C:/Users/dell/Desktop/AI/run.py", line 151, in <module>model.autoMlArgs(queryDf,targe…...

【计算机视觉】消融实验(Ablation Study)是什么?

文章目录一、前言二、定义三、来历四、举例说明一、前言 我第一次见到消融实验&#xff08;Ablation Study&#xff09;这个概念是在论文《Faster R-CNN》中。 消融实验类似于我们熟悉的“控制变量法”。 假设在某目标检测系统中&#xff0c;使用了A&#xff0c;B&#xff0…...

Java毕业论文参考文献参考例子整理

[1]李庆民.基于java的软件agent开发环境的分析[J].数字技术与应用,2017,01:189.    [2]籍慧文.Web应用开发中JAVA编程语言的应用探讨[J].科技创新与应用,2017,07:90.    [3]卜令瑞.基于Java软件项目开发岗位的企业实践总结报告[J].职业,2016,32:124-125.    [4]肖成金,吕…...

C++ Primer第五版_第六章习题答案(21~30)

文章目录练习6.21练习6.22练习6.23练习6.24练习6.25练习6.26练习6.27练习6.28练习6.29练习6.30练习6.21 编写一个函数&#xff0c;令其接受两个参数&#xff1a;一个是int型的数&#xff0c;另一个是int指针。函数比较int的值和指针所指的值&#xff0c;返回较大的那个。在该函…...

SLAM算法之HectorSLAM,Gmapping,KartoSLAM,CoreSLAM和LagoSLAM

文章将介绍使用的基于机器人操作系统&#xff08;ROS&#xff09;框架工作的SLAM算法。 在ROS中提供的五种基于2D激光的SLAM算法分别是&#xff1a;HectorSLAM&#xff0c;Gmapping&#xff0c;KartoSLAM&#xff0c;CoreSLAM和LagoSLAM。当然最后还有比较经典的google开源的ca…...

phpstorm断点调试

环境&#xff1a;win10phpstorm2022phpstudy8lnmp 1、phpinfo(); 查看是否安装xdebug&#xff0c;没有走以下流程 2、phpstudy中切换不同版本php版本&#xff0c;有些版本不支持xdebug&#xff08;如php8.0.2&#xff09;&#xff0c;有些已经自带了&#xff08;如php7.3.9&a…...

基于Flask实现的医疗保险欺诈识别监测模型

基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施&#xff0c;由雇主和个人按一定比例缴纳保险费&#xff0c;建立社会医疗保险基金&#xff0c;支付雇员医疗费用的一种医疗保险制度&#xff0c; 它是促进社会文明和进步的…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制

在数字化浪潮席卷全球的今天&#xff0c;数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具&#xff0c;在大规模数据获取中发挥着关键作用。然而&#xff0c;传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时&#xff0c;常出现数据质…...

华硕a豆14 Air香氛版,美学与科技的馨香融合

在快节奏的现代生活中&#xff0c;我们渴望一个能激发创想、愉悦感官的工作与生活伙伴&#xff0c;它不仅是冰冷的科技工具&#xff0c;更能触动我们内心深处的细腻情感。正是在这样的期许下&#xff0c;华硕a豆14 Air香氛版翩然而至&#xff0c;它以一种前所未有的方式&#x…...

从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践

作者&#xff1a;吴岐诗&#xff0c;杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言&#xff1a;融合数据湖与数仓的创新之路 在数字金融时代&#xff0c;数据已成为金融机构的核心竞争力。杭银消费金…...

Python训练营-Day26-函数专题1:函数定义与参数

题目1&#xff1a;计算圆的面积 任务&#xff1a; 编写一个名为 calculate_circle_area 的函数&#xff0c;该函数接收圆的半径 radius 作为参数&#xff0c;并返回圆的面积。圆的面积 π * radius (可以使用 math.pi 作为 π 的值)要求&#xff1a;函数接收一个位置参数 radi…...

基于单片机的宠物屋智能系统设计与实现(论文+源码)

本设计基于单片机的宠物屋智能系统核心是实现对宠物生活环境及状态的智能管理。系统以单片机为中枢&#xff0c;连接红外测温传感器&#xff0c;可实时精准捕捉宠物体温变化&#xff0c;以便及时发现健康异常&#xff1b;水位检测传感器时刻监测饮用水余量&#xff0c;防止宠物…...

大数据治理的常见方式

大数据治理的常见方式 大数据治理是确保数据质量、安全性和可用性的系统性方法&#xff0c;以下是几种常见的治理方式&#xff1a; 1. 数据质量管理 核心方法&#xff1a; 数据校验&#xff1a;建立数据校验规则&#xff08;格式、范围、一致性等&#xff09;数据清洗&…...

Python第七周作业

Python第七周作业 文章目录 Python第七周作业 1.使用open以只读模式打开文件data.txt&#xff0c;并逐行打印内容 2.使用pathlib模块获取当前脚本的绝对路径&#xff0c;并创建logs目录&#xff08;若不存在&#xff09; 3.递归遍历目录data&#xff0c;输出所有.csv文件的路径…...

AWSLambda之设置时区

目标 希望Lambda运行的时区是东八区。 解决 只需要设置lambda的环境变量TZ为东八区时区即可&#xff0c;即Asia/Shanghai。 参考 使用 Lambda 环境变量...