Promise自定义封装

目录

Promise构造函数

then方法封装

catch方法封装

resolve方法封装

reject方法封装

all方法封装

race方法封装


这篇文章主要是介绍如何自己封装Promise构造函数以及其相应的方法。Promise是JS中的重点,很多的面试都会问到。因此需要对其有比较深入地认识。看这篇文章可能需要你对promise有一定的了解,不然可能会有点吃力。

Promise构造函数

首先需要知道Promise构造函数接受的参数,以及内部执行的逻辑功能。Promise构造函数接受一个函数作为实参。该函数具有两个参数,一个为resolve另一个为reject。当函数内部调用resolve函数是,代表promise实例的状态为fulfilled代表成功,同时可以将成功的值传给该函数。当函数内部调用reject函数时,就会让promise实例的状态为rejected代表失败,同时可以将失败的值传给该函数。

在该构造函数中需要声明resolve函数以及reject函数,resolve函数内部需要先判断实例对象的状态,只有当它的状态不为pending时,才能将该实例的状态变成fulfilled。这一步判断主要是解决实例的状态不能改变的情况,只能从pending到fulfilled或者是从pending到rejected。然后再将对应成功的值赋值该实例的PromiseResult属性。然后当实例的状态改变时它会执行对应then方法中的回调,该回调是在resolve函数中调用的。then方法为异步,因此需要加上该给定时器。同时当实例的状态改变时,该实例对应的多个then方法都会执行,因此可以声明一个用于存储回调函数的数组,然后遍历该数组除了对应的回调。reject函数是同个道理。

function Promise(executor){//添加属性this.PromiseState='pending';this.PromiseResult=null;//声明属性 存储回调函数this.callBacks=[];//保存实例对象的this值const self=this;//resolve函数function resolve(data){//判断状态if(self.PromiseState!=='pending') return;//修改对象的状态(promiseState)self.PromiseState='fulfilled';//设置对象结果值self.PromiseResult=data;//调用成功的回调函数setTimeout(()=>{self.callBacks.forEach(item=>{item.onResolved(data);})});}//reject函数function reject(data){//判断状态if(self.PromiseState!=='pending') return;//修改对象的状态(promiseState)self.PromiseState='rejected';//设置对象结果值self.PromiseResult=data;//调用失败的回调setTimeout(()=>{self.callBacks.forEach(item=>{item.onRejected(data);})});}try{//同步调用executor(resolve,reject);}catch(e){//修改promise对象状态为失败reject(e);}}

then方法封装

当promise实例状态发生改变时then方法会被调用。then方法传入两个参数,第一个参数是resolved状态的回调函数,当实例的状态为成功时执行该函数。第二个参数是rejected状态的回调函数,当实例的状态为失败时执行该函数。then方法返回的是一个新的Promise实例。该实例对象的状态由回调函数的执行结果决定。如果回调函数中返回的结果是非promise类型的属性,状态为成功,返回的值为对象的成功的值。若没有return返回结果,则同样是成功的状态,只是对应的值为undefined。若返回的是一个promise对象,then返回的状态则为return中promise对象的状态,其值也是对应的内部return中promise的值。若是抛出错误,则then返回的promise对象的状态为失败的状态,对应的值为抛出的值。

then方法中的两个参数当第一个参数没有传入时,默认地给该参数设置为一个携带value参数并返回value的函数。这些做可以实现promise中对应的值传递的功能。当第二个参数没有传值时,我们默认的将该参数赋值为一个携带reason参数并返回reason的函数。这样可以实现promise中的异常穿透的功能。then方法的回调是异步执行的,因此需要在执行回调的时候包裹一个定时器。

当实例对象的状态还是pending时,将对应的回调存放到保存回调函数的数组中。当实例的状态改变时则会进行调用。

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)=>{//封装函数function callback(type){try{//获取回调函数的执行结果let result=type(self.PromiseResult);//判断if(result instanceof Promise){//如果是Promise类型的对象result.then(v=>{resolve(v);},r=>{reject(r);})}else{resolve(result);}}catch(e){reject(e);}}if(this.PromiseState==='fulfilled'){setTimeout(()=>{callback(onResolved);})}if(this.PromiseState==='rejected'){setTimeout(()=>{callback(onRejected);})}if(this.PromiseState==='pending'){//保存回调函数this.callBacks.push({onResolved:function(){callback(onResolved);},onRejected:function(){callback(onRejected);}})}});}

catch方法封装

该方法用于处理当promise实例的状态为失败时的回调,相当于是then方法的第二个回调函数。

Promise.prototype.catch=function(onRejected){return this.then(undefined,onRejected);
}

resolve方法封装

该方法是Promise构造函数的方法,不是其实例对象的方法。其的作用是返回一个成功的promise对象。若传入的值不是promise,则一定返回成功的状态。当传入的值为Promise对象时,它的状态由传入的promise的状态决定。

Promise.resolve=function(value){//返回promise对象return new Promise((resolve,reject)=>{if(value instanceof Promise){value.then(v=>{resolve(v);},r=>{reject(r);})}else{//状态设置为成功resolve(value);}})
}

reject方法封装

该方法是Promise构造函数的方法。其的作用是返回一个失败的promise对象。不管传入的参数是什么,都是返回一个失败状态的promise对象

Promise.reject=function(reason){return new Promise((resolve,reject)=>{reject(reason);})
}

all方法封装

该方法是Promise构造函数的方法。该方法接受多个promise实例。当接收的所有promise实例对象的状态都为成功时才会是成功的状态,返回的结构为所有对象的成功值,存储在数组中。但有其中的一个实例对象的状态为失败时,all方法返回的promise对象的状态会变成失败,且对应的值为其中传入失败的promise对象失败的值。

这里需要声明一个变量来进行记录,但执行成功的回调时就会增加一,当该数值与数组的长度一样时,说明所有的promise实例的状态都为成功。则让其调用成功的回调函数。由于返回的值是原本数组中实例存放的位置,因此需要 arr[i]=v;执行数组的对应下标,存放对应实例的值。

Promise.all=function(promises){return new Promise((resolve,reject)=>{//声明变量let count=0;let arr=[];//遍历for(let i=0;i<promises.length;i++){promises[i].then(v=>{count++;//将当前promise对象成功的结果存入到数组arr[i]=v;//判断if(count==promises.length){//修改状态resolve(arr);}},r=>{reject(r);});}})
}

race方法封装

该方法是Promise构造函数的方法。该方法同样接受多个promise对象。它返回的promise对象的状态以及值,由第一个最先改变状态的promise对象决定

遍历数组之后,此时只需要有一个成功,则就调用成功的回调。

Promise.race=function(promises){return new Promise((resolve,reject)=>{for(let i=0;i<promises.length;i++){promises[i].then(v=>{//修改返回对象的状态为成功resolve(v);},r=>{//修改返回对象的状态为失败reject(r);})}})
}

class封装

最后将其封装到class中,让其更加地简洁。

class Promise {//构造函数constructor(executor) {//添加属性this.PromiseState = 'pending';this.PromiseResult = null;//声明属性 存储回调函数this.callBacks = [];//保存实例对象的this值const self = this;//resolve函数function resolve(data) {//判断状态if (self.PromiseState !== 'pending') return;//修改对象的状态(promiseState)self.PromiseState = 'fulfilled';//设置对象结果值self.PromiseResult = data;//调用成功的回调函数setTimeout(() => {self.callBacks.forEach(item => {item.onResolved(data);})});}//reject函数function reject(data) {//判断状态if (self.PromiseState !== 'pending') return;//修改对象的状态(promiseState)self.PromiseState = 'rejected';//设置对象结果值self.PromiseResult = data;//调用失败的回调setTimeout(() => {self.callBacks.forEach(item => {item.onRejected(data);})});}try {//同步调用executor(resolve, reject);} catch (e) {//修改promise对象状态为失败reject(e);}}//then方法then(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) => {//封装函数function callback(type) {try {//获取回调函数的执行结果let result = type(self.PromiseResult);//判断if (result instanceof Promise) {//如果是Promise类型的对象result.then(v => {resolve(v);}, r => {reject(r);})} else {resolve(result);}} catch (e) {reject(e);}}if (this.PromiseState === 'fulfilled') {setTimeout(() => {callback(onResolved);})}if (this.PromiseState === 'rejected') {setTimeout(() => {callback(onRejected);})}if (this.PromiseState === 'pending') {//保存回调函数this.callBacks.push({onResolved: function () {callback(onResolved);},onRejected: function () {callback(onRejected);}})}});}//catch方法catch(onRejected) {return this.then(undefined, onRejected);}//添加resolve方法static resolve(value) {//返回promise对象return new Promise((resolve, reject) => {if (value instanceof Promise) {value.then(v => {resolve(v);}, r => {reject(r);})} else {//状态设置为成功resolve(value);}})}//添加reject方法static reject(reason) {return new Promise((resolve, reject) => {reject(reason);})}//添加all方法static all(promises) {return new Promise((resolve, reject) => {//声明变量let count = 0;let arr = [];//遍历for (let i = 0; i < promises.length; i++) {promises[i].then(v => {count++;//将当前promise对象成功的结果存入到数组arr[i] = v;//判断if (count == promises.length) {//修改状态resolve(arr);}}, r => {reject(r);});}})}//添加race方法static race(promises) {return new Promise((resolve, reject) => {for (let i = 0; i < promises.length; i++) {promises[i].then(v => {//修改返回对象的状态为成功resolve(v);}, r => {//修改返回对象的状态为失败reject(r);})}})}}

好啦!本文就到这里了。拜拜~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/194517.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

创意项目开源,文生图、排序/优选等...,持续开源更新!!

热烈欢迎大家在git上star&#xff01;&#xff01;&#xff01;冲鸭&#xff01;&#xff01;&#xff01; 1.dalle1在厨房家具中文场景上训练。 GitHub - leeguandong/DALLE1: dalle1在中文家具场景的微调&#xff0c;效果并不好dalle1在中文家具场景的微调&#xff0c;效果…

【JavaSE】异常(学习笔记)

一、异常概述 异常&#xff1a;程序出错了 1、异常的分类 编译时异常&#xff1a;受检异常运行时异常&#xff1a;非受检异常 2、异常体系&#xff1a;Throwable Error&#xff1a;严重问题&#xff0c;不需要处理Exception&#xff1a;异常类&#xff0c;程序本身可以处理…

MYSQL报错 [ERROR] InnoDB: Unable to create temporary file; errno: 0

起因 服务器的mysql不支持远程访问&#xff0c;在修改完相关配置后重启服务出错。 2023-12-03T10:12:23.895459Z 0 [Note] C:\Program Files\MySQL\MySQL Server 5.7\bin\mysqld.exe (mysqld 5.7.22-log) starting as process 15684 ... 2023-12-03T10:12:23.908886Z 0 [Note…

Google Guava 事件总线工具使用详解

文章目录 事件总线特点使用 事件总线 Guava 事件总线&#xff08;EventBus&#xff09;是 Google Guava 库中的一个组件&#xff0c;用于实现发布-订阅模式的事件通信。它提供了一种简单而强大的方式&#xff0c;让不同的组件之间能够解耦、相互通信、完成事件处理。 特点 注…

C语言--每日选择题--Day33

第一题 1. 在以下给出的表达式中&#xff0c;与do-while(E)语句中的(E)不等价的表达式是&#xff08; &#xff09; A&#xff1a;(!E 0) B&#xff1a;(E > 0 || E < 0) C&#xff1a;(E 0) D&#xff1a;(E ! 0) 答案及解析 C 首先要知道(E)这个条件成立无非两种&…

nodejs基于vue的社区物业缴费报修管理系统7vwc6

运行软件:vscode 前端nodejsvueElementUi 语言 node.js 框架&#xff1a;Express/koa 前端:Vue.js 数据库&#xff1a;mysql 开发软件&#xff1a;VScode/webstorm/hbuiderx均可 数据库用MySQL,后台用vue框架 基本要求&#xff1a; 1. 对项目进行详细实际的需求分析。 2. 在网…

前端面试灵魂提问(1)

1.自我介绍 2.在实习中&#xff0c;你负责那一模块 3.any与unknow的异同 相同点&#xff1a;any和unkonwn 可以接受任何值 不同点&#xff1a;any会丢掉类型限制&#xff0c;可以用any 类型的变量随意做任何事情。unknown 变量会强制执行类型检查&#xff0c;所以在使用一个…

小杨X型矩阵

对于这道题&#xff0c;我们首先需要了解它的思路 他一共要考虑两条线 左斜线和右斜线 --- --- ---- --- --- 像上面这样&#xff1b; 两条线的判断条件分别为 ij 及 ijn1 代码如下&#xff1a; #include<iostream> using namespace std; int main() {int n;cin&g…

2024年天津财经大学珠江学院专升本专业课报名缴费操作流程

天津财经大学珠江学院专升本专业课报名缴费操作流程 天津财经大学珠江学院专升本专业课报名就是缴费&#xff0c;只需要使用中国银行交专业课报名费即可。 缴费操作流程如下&#xff1a; 登录中国银行手机 APP—点击“生活”—在界面 最左上角选择定位为“天津市”—点击“生…

❀My学习Linux命令小记录(6)❀

目录 ❀My学习Linux命令小记录&#xff08;6&#xff09;❀ 26.ps指令 27.grep指令 28.awk指令 29.sed指令 30.wc指令 ❀My学习Linux命令小记录&#xff08;6&#xff09;❀ 26.ps指令 功能说明&#xff1a;报告当前系统的进程状态。 (ps.ps命令 用于报告当前系统的进…

Jupyter NoteBook未授权访问漏洞

任务一&#xff1a; 复现未授权访问的漏洞 任务二&#xff1a; 利用Jupter Notebook控制台执行系统命令&#xff0c;读取/etc/passwd内容 1.搭建环境 2.new下面直接进入终端&#xff0c;而且也不需要登录&#xff0c;我就直接进入了管理界面 3.直接把指令输入进入&#xf…

linux 下ttyAMA0,ttyS0,ttyUSB0啥区别

技术上讲&#xff0c;ttyS0 的原始含义似乎是“第一个串行端口*使用与原始 IBM PC UART、8250 芯片兼容的 UART 实现。ARM 上的 ttyAMA0 和例如 ttySAC0 将意味着“使用另一个特定硬件实现实现的第一个串行端口”。ttyUSB0 指的是第一个 USB 到串行转换器。ttyACM0 指的是使用 …

【自动化测试教程】Java+Selenium自动化测试环境搭建

本主要介绍以Java为基础&#xff0c;搭建Selenium自动化测试环境&#xff0c;并且实现代码编写的过程。 1.Selenium介绍 Selenium 1.0 包含 core、IDE、RC、grid 四部分&#xff0c;selenium 2.0 则是在两位大牛偶遇相互沟通决定把面向对象结构化&#xff08;OOPP&#xff09…

【NGINX--11】利用访问日志、错误日志和 请求跟踪进行调试和故障排除

1、配置访问日志 需要配置访问日志格式&#xff0c;以将内置变量添加到请求日志中。 配置访问日志格式&#xff1a; http {log_format geoproxy[$time_local] $remote_addr $realip_remote_addr $remote_user $proxy_protocol_server_addr $proxy_protocol_server_port $r…

TCP三次握手与四次挥手

TCP三次握手与四次挥手 TCP三次握手与四次挥手解析 客户端连接服务器&#xff08;三次握手&#xff09;客户端关闭与服务器连接&#xff08;四次挥手&#xff09; 总结 TCP三次握手与四次挥手、流量控制(滑动窗口)、拥塞控制、半连接状态、2MSL TCP三次握手与四次挥手 TCP标…

fasterxml 注解组装实体

使用 FasterXML Jackson 的注解 JsonTypeInfo 和 JsonSubTypes 可以实现多态类型的处理。在你的 User 类上&#xff0c;你可以添加这些注解来指示 Jackson 如何处理多态类型。 以下是使用 JsonTypeInfo 和 JsonSubTypes 注解的 User 类的修改&#xff1a; import com.fasterx…

【C语言】【数据结构】【手搓二叉树】用数组实现一个二叉树

这里用数组&#xff08;顺序表&#xff09;实现一个二叉树 Heap.h #include<stdio.h> #include<stdlib.h> #include<assert.h> #include<stdbool.h> typedef int HPDataType; typedef struct Heap {HPDataType* a;int size;int capacity; }HP; void …

LongAddr

目录 1. 引言 2. AtomicInteger的局限性 3. AtomicInteger与LongAdder 的性能差异 4.LongAdder 的结构 LongAddr架构 Striped64中重要的属性 Striped64中一些变量或者方法的定义 Cell类 5. 分散热点的原理 具体流程图 6. 在实际项目中的应用 7. 总结 1. 引言 在这一…

抖音外卖商品模型

目录 一、抖音外卖商品模型 二、商家运营流程 &#xff08;一&#xff09;商家入驻流程 &#xff08;二&#xff09;商品发布流程 三、推广带货流程 &#xff08;一&#xff09;短视频带货 &#xff08;二&#xff09;直播视频带货 【直播工具】 【直播流程】 直播前…

Redis--13--缓存一致性问题

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 缓存一致性问题1、先更新缓存&#xff0c;再更新DB方案二&#xff1a;先更新DB&#xff0c;再更新缓存方案三&#xff1a;先删缓存&#xff0c;再写数据库推荐1&…