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

网络编程(Modbus进阶)

思维导图 Modbus RTU&#xff08;先学一点理论&#xff09; 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议&#xff0c;由 Modicon 公司&#xff08;现施耐德电气&#xff09;于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好&#xff0c;欢迎来到《云原生核心技术》系列的第七篇&#xff01; 在上一篇&#xff0c;我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在&#xff0c;我们就像一个拥有了一块崭新数字土地的农场主&#xff0c;是时…...

相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解

【关注我&#xff0c;后续持续新增专题博文&#xff0c;谢谢&#xff01;&#xff01;&#xff01;】 上一篇我们讲了&#xff1a; 这一篇我们开始讲&#xff1a; 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下&#xff1a; 一、场景操作步骤 操作步…...

P3 QT项目----记事本(3.8)

3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)

本文把滑坡位移序列拆开、筛优质因子&#xff0c;再用 CNN-BiLSTM-Attention 来动态预测每个子序列&#xff0c;最后重构出总位移&#xff0c;预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵&#xff08;S…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件&#xff0c;这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下&#xff0c;实现高效测试与快速迭代&#xff1f;这一命题正考验着…...

Fabric V2.5 通用溯源系统——增加图片上传与下载功能

fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...

Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问&#xff08;基础概念问题&#xff09; 1. 请解释Spring框架的核心容器是什么&#xff1f;它在Spring中起到什么作用&#xff1f; Spring框架的核心容器是IoC容器&#…...

JVM虚拟机:内存结构、垃圾回收、性能优化

1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...

AI语音助手的Python实现

引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...