当前位置: 首页 > news >正文

JS手写Promise以及promise.all方法

Promise是处理异步的一种方式,解决了回调地狱的问题。

Promise有三种状态:

1.pending(待定):初始状态。

2.fulfilled(已兑现):表示异步操作成功,返回一个返回值。

3.rejected(已拒绝):表示异步操作失败,返回一个错误原因。

状态转换:可以从pending转换到fulfiied,从pending转换到rejected。一旦转换成功,状态就不可再发生改变。

常用方法:

1.Promise.resolve():将给定的一个值转换为Promise。如果本身就是Promise,那么直接返回,如果该值是一个thenable对象,那么将调用其then方法及其两个回调函数;

2.Promise.reject():返回一个已拒绝(rejected) 的Promise对象,拒绝原因为给定的参数。

3.Promise.all():接受一个Promise可迭代对象作为输入,并返回一个Promise。当所有的Promise都被兑现时,返回的Promise也将被兑现,并返回一个包含所有兑现值的数组。输入的任何被拒绝,返回的也将被拒绝。

接下来就是基本结构:

class myPromise{constructor(executer) {this.state = 'pending' //初始状态为pendingthis.value = undefined  //成功的值this.reason = undefined  //失败原因this.onFulfilledCallbacks = []; //成功回调函数数组this.onRejectedCallbacks = []  //失败回调函数数组const resolve = value => {  //resolve函数,用于改变状态,从pending到fulfilled,并记录成功的值if(this.state === 'pending') {  //只有在pending状态下才能进行状态转变this.state = 'fulfilled'this.value = valuethis.onFulfilledCallbacks.forEach(fn => fn())  //执行每一个回调函数}}const reject = reason => {  //reject函数,用于改变状态if(this.state = 'pending') {  //严谨一点this.state = 'rejected'this.reason = reasonthis.onRejectedCallbacks.forEach(fn => fn())  //执行每一个失败回调函数}};try {executor(resolve,reject);} catch (err){reject(err)}}
}

.then方法

myPromise.prototype.then = function(onFulfilled, onRejected) {onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value  //设置默认回调函数,确保函数类型,如果没有则使用默认处理函数onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason}let promise2 = new myPromise((resolve,reject) => {  //创建新的promise用于链式调用if(this.state === 'fulfilled' || this.state === 'rejected') {   //判断状态,如果为fulfilled,执行成功回调,反之则执行失败回调setTimeout(() => {try {  //获取成功回调的返回值let result = this.state ==='fulfilled' ? onFulfilled(this.value) :onRejected(this.reason)resolvePromise(promise2, result, resolve, reject) //处理返回值确定promise2的状态} catch (e) {reject(e) //如果执行过程出错就reject}}, 0)}if(this.state === 'pending') {   //如果状态为pending,把回调函数存储起来this.onFulfilledCallbacks.push(()=> {setTimeout(() => {try {let x = onFulfilled(this.value)resolvePromise(promise2, x, resolve, reject)} catch (e) {reject(e)}},0)})this.onRejectedCallbacks.push(() => {setTimeout(() => {try {let x = onRejected(this.reason)resolvePromise(promise2, x, resolve, reject)} catch (e) {reject(e)}},0)})}return promise2})}

resolvePromise方法,用于处理then方法中返回的结果,以界定新的promise状态

function resolvePromise(promise2, x, resolve, reject) {if(promise2 === x) {  //如果一样,抛出TypeError防止自循环return reject(new TypeError('changing cycle detected from promise'))}
​let called  //如果X是对象或者数组if(x != null && (typeof x === 'object' || typeof x === 'function')) {try {let then = x.then  //取出x的then方法if(typeof then === 'function') {  //如果then是函数,调用,传入resolvePromise和reject函数then.call(x,y => {if(called) returncalled = trueresolvePromise(promise2, y, resolve, reject)}, r=> {if(called) returncalled = truereject(r)})} else {reslove(x) //如果x不是,以x为值fulfill promise2}} catch(e) {if(called) return called = truereject(e)}} else {resolve(x)}}

resolve,reject方法用于快速生成一个promise对象

 myPromise.prototype.resolve = function(value) {return new myPromise((resolve,reject) => {resolve(value)})}
​myPromise.prototype.reject = function(reason) {return new myPromise((resolve,reject) => {reject(reason)})}
​

.all()方法,传入数组promise,将多个promise包装成一个新的promise,且只有多个全部成功,新实例才会成功

myPromise.prototype.all = function(promises) {return new myPromise((resolve, reject) => {  //返回一个新的promiselet result = []  //存储每一个promise的结果let count = 0  //记录完成的数量
​function processresult(index, data) {  //处理单个promiseresult[index] = datacount++if(count === promises.length) {  //如果所有promise全部完成,resolve一个新的promiseresolve(result)}}
​for(let i=0;i<promises.length;i++) {  //遍历数组,处理结果promises[i].then(data => {processresult(i,data)}, reject)}})}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【算法】贪心+堆排序实现大根堆及标准库容器类的融合使用
  • 车载网络测试实操源码_使用CAPL脚本实现安全访问解锁,并模拟各种测试场景
  • C语言中易混淆概念的关键字
  • Qt/C++ 多线程同步机制详解及应用
  • redis 十大应用场景
  • 特种作业管理系统 —— 企业安全与效率的卓越保障
  • EfficientViT(2023CVPR):具有级联组注意力的内存高效视觉Transformer!
  • 8. 详细描述一条 SQL 语句在 MySQL 中的执行过程。
  • jQuery国内大厂CDN加速链接
  • 本地生活商城开发搭建 同城O2O线上线下推广
  • 【SpringBoot整合Redis测试Redis集群案例】
  • 一、Kafka入门
  • Cursor免费 GPT-4 IDE 工具的保姆级使用教程
  • windows GetUserNameEx api使用c++
  • 【C#生态园】C#任务调度库大比拼:选择最适合你项目的工具
  • crontab执行失败的多种原因
  • exif信息对照
  • iBatis和MyBatis在使用ResultMap对应关系时的区别
  • mockjs让前端开发独立于后端
  • Octave 入门
  • Spark VS Hadoop:两大大数据分析系统深度解读
  • zookeeper系列(七)实战分布式命名服务
  • 对象引论
  • 欢迎参加第二届中国游戏开发者大会
  • 异常机制详解
  • 不要一棍子打翻所有黑盒模型,其实可以让它们发挥作用 ...
  • ​如何在iOS手机上查看应用日志
  • ​一帧图像的Android之旅 :应用的首个绘制请求
  • ###51单片机学习(1)-----单片机烧录软件的使用,以及如何建立一个工程项目
  • #WEB前端(HTML属性)
  • (1)bark-ml
  • (二)学习JVM —— 垃圾回收机制
  • (附源码)springboot优课在线教学系统 毕业设计 081251
  • (简单) HDU 2612 Find a way,BFS。
  • (剑指Offer)面试题34:丑数
  • (南京观海微电子)——COF介绍
  • (四)activit5.23.0修复跟踪高亮显示BUG
  • (四)linux文件内容查看
  • (五)关系数据库标准语言SQL
  • (详细文档!)javaswing图书管理系统+mysql数据库
  • (一)utf8mb4_general_ci 和 utf8mb4_unicode_ci 适用排序和比较规则场景
  • (幽默漫画)有个程序员老公,是怎样的体验?
  • (转载)Linux网络编程入门
  • *Algs4-1.5.25随机网格的倍率测试-(未读懂题)
  • .NET Core WebAPI中使用swagger版本控制,添加注释
  • .NET Core 中插件式开发实现
  • .NET Core实战项目之CMS 第十二章 开发篇-Dapper封装CURD及仓储代码生成器实现
  • .net framework 4.0中如何 输出 form 的name属性。
  • .NET Micro Framework 4.2 beta 源码探析
  • .NET 依赖注入和配置系统
  • .net后端程序发布到nignx上,通过nginx访问
  • .NET设计模式(2):单件模式(Singleton Pattern)
  • @cacheable 是否缓存成功_Spring Cache缓存注解
  • @RequestBody与@ResponseBody的使用
  • [8-27]正则表达式、扩展表达式以及相关实战