手写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");
});
-
定义构造函数中的两个基本属性
PromiseState,PromiseResultfunction Promise() {this.PromiseState = "pending";this.PromiseResult = null; } -
由于实例对象中传递的参数是一个执行器函数,并且会立即执行这个函数。
function Promise(executor) {this.PromiseState = "pending";this.PromiseResult = null;executor(); } -
该执行器函数中有两个函数参数,调用任意一个函数会改变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); } -
还有一种情况:promise实例执行结果为抛出异常,需要让其状态为失败。
function Promise(executor) {// ...// 参数为一个函数且立即执行,该函数需要两个函数参数改变promise的状态和结果值;抛出异常时状态为失败try {executor(resolve, reject);} catch (error) {reject(error);} } -
在对象原型上添加
then方法。Promise.prototype.then = function(onResolved, onRejected) {if(this.PromiseState === "fulfilled") {onResolved();}if(this.PromiseState === "rejected") {onRejected();} } -
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};} } -
当一个
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 success2function 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});} } -
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);}}});}}) }
-
-
封装
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);}});}}) } -
添加
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); } -
添加
Promise.resolve和Promisereject方法。// 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);}) } -
添加
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);});});}) } -
添加
Promise.race方法:实例中谁先改变状态,返回的状态和结果值就为该实例的状态和结果值。Promise.race = function(promises) {return new Promise((resolve, reject) => {promises.forEach(item => {item.then(v => {resolve(v);}, r => {reject(r);});});}) } -
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)是什么?
文章目录一、前言二、定义三、来历四、举例说明一、前言 我第一次见到消融实验(Ablation Study)这个概念是在论文《Faster R-CNN》中。 消融实验类似于我们熟悉的“控制变量法”。 假设在某目标检测系统中,使用了A,B࿰…...
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 编写一个函数,令其接受两个参数:一个是int型的数,另一个是int指针。函数比较int的值和指针所指的值,返回较大的那个。在该函…...
SLAM算法之HectorSLAM,Gmapping,KartoSLAM,CoreSLAM和LagoSLAM
文章将介绍使用的基于机器人操作系统(ROS)框架工作的SLAM算法。 在ROS中提供的五种基于2D激光的SLAM算法分别是:HectorSLAM,Gmapping,KartoSLAM,CoreSLAM和LagoSLAM。当然最后还有比较经典的google开源的ca…...
phpstorm断点调试
环境:win10phpstorm2022phpstudy8lnmp 1、phpinfo(); 查看是否安装xdebug,没有走以下流程 2、phpstudy中切换不同版本php版本,有些版本不支持xdebug(如php8.0.2),有些已经自带了(如php7.3.9&a…...
业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...
苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...
【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...
SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)
上一章用到了V2 的概念,其实 Fiori当中还有 V4,咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务),代理中间件(ui5-middleware-simpleproxy)-CSDN博客…...
深度学习习题2
1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...
LeetCode - 199. 二叉树的右视图
题目 199. 二叉树的右视图 - 力扣(LeetCode) 思路 右视图是指从树的右侧看,对于每一层,只能看到该层最右边的节点。实现思路是: 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...
算法:模拟
1.替换所有的问号 1576. 替换所有的问号 - 力扣(LeetCode) 遍历字符串:通过外层循环逐一检查每个字符。遇到 ? 时处理: 内层循环遍历小写字母(a 到 z)。对每个字母检查是否满足: 与…...
C++.OpenGL (20/64)混合(Blending)
混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...
[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】
大家好,我是java1234_小锋老师,看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】,分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...
