手写 Promise 的实现

手写 Promise 的实现

从实现原理的角度分析 Promise 是什么

从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。ES6 原生提供了Promise对象。

Promise内部有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,并且一旦状态改变,就不会再变,任何时候都可以得到这个结果。

Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected

有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。

实现步骤

  1. 创建一个 Promise 函数,内部声明三个变量:
    • PromiseState :表示当前 Promise 的状态
    • PromiseResult:表示当前 Promise 的执行结果
    • callBack: 表示当前 Promise 状态更改后要执行的回调函数数组
    • 状态根据传入的参数函数执行决定,如果函数的执行过程中出现了报错,则通过try/catch捕获到后,调用reject函数,将当前Promise的状态置为 rejected,否则函数的状态根据参数函数excutor的执行结果决定,如果excutor返回不为Promise对象的实例,则直接调用resolve将当前Promise实例的状态置为fullfilled,如果excutor返回的是Promise对象的实例,则根据promise.then( v => { resolve(v);}, r => {reject(r);})的执行结果判断当前Promise的执行状态
    function Promise(excutor) {this.PromiseState  = 'pending'this.PromiseResult = nullthis.callBack = []const self = thistry{excutor(resolve, reject)} catch(e) {reject(e)}function resolve(value) {if(self.PromiseState  !== 'pending') returnself.PromiseState  = 'fullfilled'self.PromiseResult = valueexcuteCallback(self)}function reject(reason) {if(self.PromiseState  !== 'pending') returnself.PromiseState  = 'rejected'self.PromiseResult = reasonexcuteCallback(self)}
    }
    function excuteCallback(self) {self.callBack.forEach(item => {if(self.PromiseState  === 'fullfilled') {item.resolveCallback&&item.resolveCallback(self.PromiseResult)}else if(self.PromiseState  === 'rejected'){item.rejectCallback && item.rejectCallback(self.PromiseResult)}});
    }
    
  2. 实现then函数,then函数接收两个回调函数,then函数返回一个新的Promise实例对象
    • 第一个函数参数 onResolved:当前 Promise 实例状态为 fullfilled 时执行
    • 第二个函数参数 onRejected:当前 Promise 实例状态为 rejected 时执行
    • then 函数返回的 Promise 实例对象的状态根据参数函数的执行结果决定,通过 try{}catch(){} 捕获错误
      • 如果未有任何报错,则调用resolve并且将onResolved执行结果作为resolve函数的参数,更改状态为fullfilled
      • 若捕获到错误,则执行reject并且将onRejected执行结果作为reject函数的参数,更改状态为rejected
      • 如果 onResolvedonRejected 函数的执行结果返回的是一个 Promise 实例对象,则根据result.then( v => { resolve(v);}, r => {reject(r);})的执行结果判断当前Promise的执行状态
    Promise.prototype.then = function(onResolved, onRejected) {return new Promise((resolve,reject) => {if(this.PromiseState  === 'fullfilled') {const thenResult = onResolved(this.PromiseResult)resolve(thenResult)} else if(this.PromiseState  === 'rejected') {const rejectResult = onRejected(this.PromiseResult)resolve(rejectResult)} else {this.callBack.push({resolveCallback: (result)=>{resolve(onResolved(result))},rejectCallback: (reason) => {resolve(onRejected(reason))}})}    })
    }
    
  3. 实现 catch 函数
    • catch函数其实是then函数的变形写法,通过将第一个参数置为 undefined 表示只捕获错误问题,不处理成功时候的回调
    Promise.prototype.catch = function(onRejected) {return this.then(undefined, onRejected)
    }
    
  4. 实现 all 函数
    • all 函数接收一个Promise数组,并且返回一个新的Promise实例
    • 如果Promise数组中有一个状态变为rejected,返回的实例的实例状态就是rejected,实例结果为第一个执行状态为rejected的执行结果
    • 等待所有的Promise数组都执行完并且更改状态之后再更改返回的Promise实例的状态,并且每个Promise实例的状态是fullfilled,返回的实例的状态就是fullfilled,结果为这些Promise实例执行的结果数组
    Promise.all = function(promises) {return new Promise((resolve, reject) => {let count = 0, arr = []for(let i=0; i<promises.lenghth; i++) {promises[i].then(value=>{count++arr[i] = valueif(count === promises.lenghth) {resolve(arr)}}, reason=>{reject(reason)})}})
    }
    
  5. 实现 race 函数
    • race 函数接收一个Promise数组,并返回一个新的Promise实例,返回的实例状态为第一个Promise状态改变的状态,返回的值也是第一个Promise状态改变的值
    Promise.race = function(promises) {return new Promise((resolve, reject) => {for(let i=0; i<promises.lenghth;i++) {promises[i].then(value => {resolve(value)}, reason => {reject(reason)})}})
    }
  6. 验证自定义 Promise 函数
    let p = new Promise((resolve, reject)=> {setTimeout(()=>{resolve(112)},100)
    })
    p.then(value=>{console.log(11111,value)return 123123123
    },reason=>{console.log(10000, reason)
    }).then(value=>{console.log(211111,value)
    },reason=>{console.log(210000, reason)
    })
    

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

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

相关文章

开箱即用:一个易用的开源表单工具!【送源码】

随着互联网的普及&#xff0c;表单应用场景越来越广泛&#xff0c;从网站注册、调查问卷到考试测评&#xff0c;无处不在。传统的表单制作方式需要一定的代码基础&#xff0c;对于不懂编程的小伙伴来说&#xff0c;无疑是一道门槛。 今天&#xff0c;给大家分享一款开源的表单…

如何理解redis是单线程的

写在文章开头 在面试时我们经常会问到这样一道题 你刚刚说redis是单线程的&#xff0c;那你能不能告诉我它是如何基于单个线程完成指令接收与连接接入的&#xff1f;这时候我们经常会得到沉默&#xff0c;所以对于这道题&#xff0c;笔者会直接通过3.0.0源码分析的角度来剖析…

[数据集][目标检测]花生米计数霉变检测数据集VOC+YOLO格式387张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;387 标注数量(xml文件个数)&#xff1a;387 标注数量(txt文件个数)&#xff1a;387 标注类别…

使用Leaflet和瓦片地图实现离线地图的技术指南

引言 在现代的Web应用中&#xff0c;地图服务扮演着越来越重要的角色。然而&#xff0c;在一些特殊环境下&#xff0c;如偏远地区或网络环境不稳定的情况下&#xff0c;依赖在线地图服务可能会受到限制。因此&#xff0c;实现离线地图功能成为了一个重要的需求。本文将介绍如何…

【数据库】Oracle 分区表与 TRUNC 函数的优化应用

在 Oracle 数据库中&#xff0c;分区表是一种强大的数据管理工具&#xff0c;它允许将大型表分割成更小、更易于管理的部分&#xff0c;称为分区。每个分区可以独立地进行管理&#xff0c;包括备份、恢复和优化。分区表特别适用于处理大量数据&#xff0c;可以显著提高查询性能…

Redis入门与应用(1)

Redis的技术全景 Redis是一个开源的基于键值对&#xff08;Key-Value&#xff09;的NoSQL数据库&#xff0c;使用ANSI C语言编写&#xff0c;支持网络&#xff0c;基于内存但支持持久化。它性能优越&#xff0c;并提供多种语言的API。我们可以将Redis视为一个巨大的Map&#x…

《Java面试题集中营》- Java并发

《Java并发编程的艺术》、《Java并发编程之美》 运行中的线程能否强制杀死 Jdk提供了stop()方法用于强制停止线程&#xff0c;但官方并不建议使用&#xff0c;因为强制停止线程会导致线程使用的资源&#xff0c;比如文件描述符、网络连接处于不正常的状态。建议使用标志位的方…

秋招突击——第九弹——Redis缓存

文章目录 引言正文缓存基础旁路缓存模式&#xff08;重点&#xff09;读穿透&#xff08;了解&#xff09;写穿透&#xff08;了解&#xff09;异步缓存写入模式面试重点 缓存异常场景缓存穿透缓存击穿缓存雪崩面试重点 缓存一致性怎么保证&#xff1f;缓存一致性问题是什么方案…

[职场] 策略运营求职简历范文精选 #知识分享#微信#微信

策略运营求职简历范文精选 策略运营是用户运营的一种模式&#xff0c;主要针对于用户量级在千人到百万人规模的运营。下面是策略运营求职简历范文精选&#xff0c;供大家参考。 个人信息 姓名&#xff1a;蓝山 年龄&#xff1a;33岁 地址&#xff1a;北京 工作经验&#x…

C++STL梳理

CSTL标准手册&#xff1a; https://cplusplus.com/reference/stl/ https://cplusplus.com/reference/vector/vector/at/ 1、STL基础 1.1、STL基本组成(6大组件13个头文件) 通常认为&#xff0c;STL 是由容器、算法、迭代器、函数对象、适配器、内存分配器这 6 部分构成&…

JS延迟加载的方式有哪些

JavaScript延迟加载&#xff08;也称为懒加载&#xff09;是一种优化网页性能的技术&#xff0c;它允许脚本在页面加载完成后再执行&#xff0c;从而加快页面初始加载速度。 以下是几种常见的JavaScript延迟加载方式&#xff1a; 异步加载&#xff08;async&#xff09;: 使用a…

信息检索(54):On the Effect of Low-Frequency Terms on Neural-IR Models

On the Effect of Low-Frequency Terms on Neural-IR Models 摘要1 引言2 背景和相关工作3 实验设计4 词汇量的影响5 包含低频词的查询6 结论 发布时间&#xff08;2019&#xff09; 低频词对于神经检索模型的影响 摘要 低频词是信息检索模型面临的一个反复出现的挑战&#…

Java代码如何优化的?

1、单一职责 2、注释 3、公共类/方法抽离 4、单元测试 5、SQL优化 6、代码reviewe 7、库存以前是直接操作数据库--->lua 8、日志----->ELK

机器学习python实践——关于数据集划分和数据标准化的相关问题的思考

最近在跟着参考书利用python进行机器学习实践&#xff0c;但是在实践过程中对数据集划分和数据的标准化产生了一些疑惑&#xff0c;所以&#xff0c;本文想记录并分享一下个人关于这方面的思考&#xff0c;如果有误请见谅&#xff0c;欢迎大家前来一起进行探讨。当然&#xff0…

icloud 邮箱登入失败

APP NAME mail2HOSTING APP NAME cloudos2CLIENT TIME Tue Jun 11 2024 09:00:47 GMT0800 (中国标准时间) (1718067647802)USER AGENT Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36HOSTNAME www.icloud.…

使用阿里开源的Spring Cloud Alibaba AI开发第一个大模型应用

背景 前段时间看到Spring推出了SpringAI&#xff0c;可以方便快速的接入ChatGPT等国外的大模型&#xff0c;现在阿里巴巴也紧追脚步推出了Spring Cloud Alibaba AI&#xff0c;Spring Cloud Alibaba AI 目前基于 Spring AI 0.8.1 版本 API 完成通义系列大模型的接入。通义接入…

自定义npm脚本:打造你的package.json自动化神器

自定义npm脚本&#xff1a;打造你的package.json自动化神器 在JavaScript和Node.js的世界中&#xff0c;npm不仅仅是一个包管理器&#xff0c;它还是一个强大的自动化工具。通过package.json文件中的自定义npm脚本&#xff0c;你可以将日常开发任务自动化&#xff0c;从而节省…

常用框架-MyBatis

常用框架-MyBatis 1、MyBatis是什么?2、说说MyBatis的优点和缺点?3、#{}和${}的区别是什么?4、实体类的属性名和表中的字段名不一致怎么办?5、Mybatis是如何进行分页的?分页插件的原理是什么?6、Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式?7、…

Zookeeper 二、Zookeeper环境搭建

Zookeeper安装方式有三种&#xff0c;单机模式和集群模式以及伪集群模式 单机模式&#xff1a;Zookeeper只运行在一台服务器上&#xff0c;适合测试环境集群模式&#xff1a;Zookeeper运行于一个集群上&#xff0c;适合生产环境&#xff0c;这个计算机集群被称为一个“集合体”…

【Spine学习15】变换约束

变换约束&#xff1a;能让一个骨骼受另一个骨骼的变化影响。 1、选择m创建一个变换约束&#xff1a; 2、点击这个约束&#xff0c; 将移动数值拉的越满&#xff0c;m越接近s骨骼 当约束为0也就是默认的时候&#xff0c;m骨骼将不会受影响&#xff0c;变换约束可有可无。 tips…