当前位置: 首页 > 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…...

Vim 调用外部命令学习笔记

Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

PHP和Node.js哪个更爽?

先说结论&#xff0c;rust完胜。 php&#xff1a;laravel&#xff0c;swoole&#xff0c;webman&#xff0c;最开始在苏宁的时候写了几年php&#xff0c;当时觉得php真的是世界上最好的语言&#xff0c;因为当初活在舒适圈里&#xff0c;不愿意跳出来&#xff0c;就好比当初活在…...

【Linux】C语言执行shell指令

在C语言中执行Shell指令 在C语言中&#xff0c;有几种方法可以执行Shell指令&#xff1a; 1. 使用system()函数 这是最简单的方法&#xff0c;包含在stdlib.h头文件中&#xff1a; #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

基于Docker Compose部署Java微服务项目

一. 创建根项目 根项目&#xff08;父项目&#xff09;主要用于依赖管理 一些需要注意的点&#xff1a; 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件&#xff0c;否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)

骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术&#xff0c;它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton)&#xff1a;由层级结构的骨头组成&#xff0c;类似于人体骨骼蒙皮 (Mesh Skinning)&#xff1a;将模型网格顶点绑定到骨骼上&#xff0c;使骨骼移动…...

【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具

第2章 虚拟机性能监控&#xff0c;故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令&#xff1a;jps [options] [hostid] 功能&#xff1a;本地虚拟机进程显示进程ID&#xff08;与ps相同&#xff09;&#xff0c;可同时显示主类&#x…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习

禁止商业或二改转载&#xff0c;仅供自学使用&#xff0c;侵权必究&#xff0c;如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比

在机器学习的回归分析中&#xff0c;损失函数的选择对模型性能具有决定性影响。均方误差&#xff08;MSE&#xff09;作为经典的损失函数&#xff0c;在处理干净数据时表现优异&#xff0c;但在面对包含异常值的噪声数据时&#xff0c;其对大误差的二次惩罚机制往往导致模型参数…...

安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)

船舶制造装配管理现状&#xff1a;装配工作依赖人工经验&#xff0c;装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书&#xff0c;但在实际执行中&#xff0c;工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...