手写Promise实现

news2024/12/23 13:19:15

手写Promise实现

  • 一、前言
  • 二、代码
  • 三、测试
  • 四、测试结果

一、前言

  阅读参考资料,本文整理出使用 构造函数 手撕出 Promise 的方法,在整理过程中不断添加注解以示思路。有错请指出哟,一起进步!!!class 实现 Promise 请查看参考资料,该作者写得非常好、非常详细!!!
  参考资料:promise原理手写实现promise以及async await

二、代码

// 构造函数
function MyPromise(executor) {
  // 添加属性
  this.PromiseState = 'pending'
  this.PromiseResult = null
  // 保存实例对象的this
  const self = this
  // 声明属性
  // this.callbacks = {}
  this.callbacks = []
  
  function resolve(data){
    // 判断状态
	// 普通函数的this一般指window对象
	// 错误写法:直接this.PromiseState !== 'pending'
    if(self.PromiseState !== 'pending')return
    // 修改对象状态
    self.PromiseState = 'fulfilled'
    // 设置对象结果
    self.PromiseResult = data
    // 调用回调函数
    // if(self.callbacks.onFulfilled) {
    //   onFulfilled(data)
    // }
	setTimeout(() => {
	  self.callbacks.forEach(item => {
        item.onFulfilled(data)
      })
	})
  }
  function reject(reason) {
    if(self.PromiseState !== 'pending')return
    self.PromiseState = 'rejected'
    self.PromiseResult = reason
	// js执行顺序:同步任务 > Promise.then() > setTimeout() 
	setTimeout(() => {
	  self.callbacks.forEach(item => {
        item.onRejected(reason)
      })
	}) 
  }
  try {
	// executor是一个函数,resolve函数和reject函数作为参数传递
	// 生成Promise实例时就执行
    executor(resolve, reject)
  } catch(e) {
    reject(e)
  }
}

// 添加then方法
// then方法返回的是一个Promise对象,方便链式调用
MyPromise.prototype.then = function(onFulfilled, onRejected) {
  // 要将实例的this保存下来,普通函数的this指向window对象
  const self = this
  // 判断回调函数参数
  if(typeof onRejected !== 'function') {
    onRejected = reason => {
      throw reason
    }
  }
  if(typeof onFulfilled !== 'function') {
    onFulfilled = data => data
  }
  return new MyPromise((resolve, reject) => {
    // 封装回调函数
    function callback(type) {
      try {
		// 获取回调函数的结果
        let result = type(self.PromiseResult)
        if(result instanceof MyPromise) {
          result.then(data => {
            resolve(data)
          }, reason => {
            reject(reason)
          })
        } else {
          resolve(result)
        }
      } catch(e) {
        reject(e)
      } 
    }
    if(this.PromiseState === 'fulfilled') {
      callback(onFulfilled)
    }
    if(this.PromiseState === 'rejected') {
      callback(onRejected)
    }
	if(this.PromiseState === 'pending') {
      this.callbacks.push({
        onFulfilled: function() {
          callback(onFulfilled)
        },
        onRejected: function() {
          callback(onRejected)
        }
      })
    }
  })
}

// 添加catch方法
// 1、当使用 promise 的 then 链式调用时, 可以在最后指定失败的回调
// 2、前面任何操作出了异常, 都会传到最后失败的回调中处理
MyPromise.prototype.catch = function(onRejected) {
  return this.then(undefined, onRejected)
}

// 添加resolve静态方法
// 静态方法直接绑定到构造函数上,而不是绑定到实例对象上。
// 只能通过构造函数本身调用,实例对象不能调用
MyPromise.resolve = function(data) {
  // 返回Promise对象
  return new MyPromise((resolve, reject) => {
    if(data instanceof MyPromise) {
      data.then(data => {
        resolve(data)
      }, reason => {
        reject(reason)
      })
    } else {
      resolve(data)
    }
  })
}

// 添加reject方法
MyPromise.reject = function(reason) {
  return new MyPromise((resolve, reject) => {
    reject(reason)
  })
}

// 添加all方法
MyPromise.all = function(promises) {
  // promises是n个Promise对象
  // 结果返回一个新的 promise,只有所有的 promise 都成功才成功,只要有一个失败了就直接失败
  return new MyPromise((resolve, reject) => {
	let count = 0
	let arr = []
	for(let i = 0; i < promises.length; i++) {
	  promises[i].then(data => {
		count++
		arr[i] = data
		// 关键:判断是否所有promises都成功
		if(count === promises.length) {
		  resolve(arr)
		}
	  }, reason => {
		reject(reason)
	  })
	}
  })	
}

// 添加race方法
MyPromise.race = function(promises) {
  // 返回一个新的 promise
  // 第一个完成的 promise 的结果状态就是最终的结果状态,谁先完成就输出谁(不管是成功还是失败)
  return new MyPromise((resolve, reject) => {
	for(let i = 0; i < promises.length; i++) {
	  promises[i].then(data => {
		resolve(data)
	  }, reason => {
		reject(reason) 
	  })
	}
  })
}

三、测试

// Promise链式调用:链式调用意味着你可以在一个Promise完成后,用then方法链式调用另一个Promise。
const p = new MyPromise((resolve, reject) => {
  resolve('resolved')
}).then(data => {
  return new MyPromise((resolve, reject) => {
	resolve('resolved again')
  })
}).then(data=>{
  console.log(data)
})
console.log('-----------------------------')

const p1 = new MyPromise((resolve, reject) => {
  resolve('ok')
})
const p2 = MyPromise.resolve('oh yeah')
const p3 = MyPromise.reject('error')
const p4 = MyPromise.resolve('oh yeah yeah')

const result1 = MyPromise.all([p1, p2, p3])
console.log('all_rejected\n', result1)
console.log('-----------------------------')
const result2 = MyPromise.all([p1, p2, p4])
console.log('all_fulfilled\n',result2)
const result3 = MyPromise.race([p1, p2, p3])
console.log('-----------------------------')
console.log('race\n',result3)

四、测试结果

在这里插入图片描述

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

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

相关文章

【做一名健康的CSDNer】程序员哪几种行为最伤肾(程序员必看)

虽然没有专门针对程序员这一职业群体特有的伤肾行为的研究报道&#xff0c;但根据一般人群的健康风险和生活习惯&#xff0c;程序员由于其特殊的工作模式和环境&#xff0c;可能更容易出现如下伤肾的行为&#xff1a; 熬夜加班&#xff1a; 程序员由于项目进度、bug修复等原因&…

1、opencv介绍与开发环境搭建

1、opencv介绍 OpenCV 是 Intel 开源计算机视觉库&#xff0c;是一个跨平台的开源计算机视觉和机器学习软件库。它由一系列 C 函数和少量 C 类构成&#xff0c;可用于开发实时的图像处理、计算机视觉以及模式识别程序。 该库有 2500 多种优化算法&#xff0c;其中包括一套全面…

HarmonyOS ArkUI实战开发-NAPI 加载原理(上)

笔者在前 6 小结讲述了NAPI 的基本使用&#xff0c;包括同步和异步实现&#xff0c;本节笔者从源码的角度简单讲解一下NAPI 的加载流程&#xff0c;源码版本为 ArkUI 4.0 Release 版本。 hap 工程结构 工程配置签名后打一个 hap 包出来&#xff0c;然后解压该 hap 文件&#…

重发布及路由策略实验

目录 一、实验拓扑 二、实验需求 1、按照图示配置 IP 地址&#xff0c;R1&#xff0c;R3&#xff0c;R4 上使用 loopback 口模拟业务网段 2、R2&#xff0c;R3 和R4运行 oSPF&#xff0c;各自协议内部互通 3、在 RIP 和 oSPF 间配置双向路由引入&#xff0c;要求除 R4 上的…

C++初阶学习第二弹——C++入门(下)

C入门&#xff08;上&#xff09;&#xff1a;C初阶学习第一弹——C入门&#xff08;上&#xff09;-CSDN博客 目录 一、引用 1.1 引用的实质 1.2 引用的用法 二、函数重载 三、内敛函数 四、auto关键字 五、总结 前言&#xff1a; 在上面一章我们已经讲解了C的一些基本…

【C语言】strstr函数刨析-----字符串查找

目录 一、strstr 函数介绍 ✨函数头文件&#xff1a; ✨函数原型&#xff1a; ✨函数解读 ✨功能演示 二、函数的原理以及模拟实现 ✨函数原理 ✨函数的模拟实现 三、strstr函数的注意事项 四、共勉 一、strstr 函数介绍 strstr函数是在一个字符串中查找另一个字符…

Leetcode 86. 分隔链表

题目链接&#xff1a; 86. 分隔链表 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/partition-list/description/ 题目&#xff1a; 给你一个链表的头节点 head 和一个特定值 x &#xff0c;请你对链表进行分隔&#xff0c;使得所有 小于 x 的节点都出…

CDN技术:全球化的数字内容快速分发系统

CDN技术&#xff1a;全球化的数字内容快速分发系统 在今天的互联网世界中&#xff0c;内容分发网络&#xff08;CDN&#xff09;技术起着至关重要的作用。它通过全球分布的服务器网络&#xff0c;快速、安全地将内容送达世界各地的用户&#xff0c;极大地提升了网页加载速度和…

SpringBoot+vue开发记录(二)

说明&#xff1a;本篇文章的主要内容为SpringBoot开发中后端的创建 项目创建: 1. 新建项目&#xff1a; 如下&#xff0c;这样简单创建就行了&#xff0c;JDK什么的就先17&#xff0c;当然1.8也是可以的&#xff0c;后面可以改。 这样就创建好了&#xff1a; 2. pom.xml…

【Android12】Bugreport实现原理

Bugreport实现原理 Bugreport Bugreport介绍 Android Bugreport是一个用于记录和收集 Android设备上系统信息、日志和调试信息的工具。 系统发生某些问题时&#xff0c;可以通过bugreport把系统当前时刻点&#xff08;运行BugRepot的时刻&#xff09;的系统相关的状态和信息…

Redis中BitMap在钉钉机器人中的应用

性能分析 数据库中有1000w用户&#xff0c;每个用户签到一次&#xff0c;对应两个字段 连续签到多少次 、签到时间。 签到时间字段占用10个字节&#xff0c;连续签到多少天 占用5个字节&#xff08;假设一个用户能活100年&#xff0c;每天都签到&#xff0c;一个用户最多签到3…

【爬取研招网指定学校专业信息】

前言 本文介绍了如何使用 Python 的 requests 库和 BeautifulSoup 库来爬取研究方向信息&#xff0c;并将其保存为 CSV 文件。爬取的网站为“中国研究生招生信息网”&#xff08;https://yz.chsi.com.cn/&#xff09;。代码从指定的专业目录页面爬取研究方向的相关信息&#x…

ROM修改进阶教程------services.jar文件过小 合并odex apk合并odex 几种方法步骤解析

在上期博文中有说明去卡密等相关操作。但在安卓低版本中有些services.jar文件过小。大小不足1K,这种是无法直接反编译的。我们简单使用压缩软件打开查看。其中文件小的里面没有dex文件。这种需要我们先合并odex使其成为一个可以直接反编译的文件再来操作。操作也可以用于其他a…

Day 31 贪心算法理论基础 455.分发饼干 376. 摆动序列 53. 最大子序和

贪心算法理论基础 ​ 贪心算法的本质&#xff1a;选择每一个阶段的局部最优&#xff0c;从而达到系统的整体最优&#xff1b; ​ 贪心的套路就是没有套路&#xff0c;最好的策略就是举反例&#xff0c;因为大多数时候并不要求严格证明&#xff0c;只需要得到普遍性结论即可&a…

Linux之ebpf(1)基础使用

Linux之ebpf(1)基础使用 Author: Once Day Date: 2024年4月20日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文章可以参考专栏&#xff1a;Linux基础知识_Once-D…

C语言:数据结构(单链表)

目录 1. 链表的概念及结构2. 实现单链表3. 链表的分类 1. 链表的概念及结构 概念&#xff1a;链表是一种物理存储结构上非连续、非顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表的指针链接次序实现的。 链表的结构跟火车车厢相似&#xff0c;淡季时车次的车厢会相应…

Github账号注册

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

NC398 腐烂的苹果

腐烂的苹果 一个腐烂的苹果每分钟可以向上下左右四个方向扩展&#xff0c;扩展之后&#xff0c;又会有新的腐烂的苹果&#xff0c;一直去腐蚀好的苹果&#xff0c;求多少分钟后&#xff0c;网格中全是烂苹果。 第一次做这道题的时候&#xff0c;想到这道题考察的其实是多源BFS…

MATLAB——M文件

M文件 MATLAB允许编写两种程序文件- 脚本−脚本文件是扩展名为.m的程序文件。在这些文件中&#xff0c;您编写了一系列要一起执行的命令。脚本不接受输入&#xff0c;也不返回任何输出。它们对工作区中的数据进行操作。 函数−函数文件也是扩展名为.m的程序文件。函数可以接…

运营商三要素核验接口-手机实名验证API

运营商三要素核验接口是一种API&#xff08;Application Programming Interface&#xff0c;应用程序编程接口&#xff09;&#xff0c;主要用于通过互联网技术对接通信运营商的实名制数据库&#xff0c;以验证用户提供的手机号码、身份证号码、姓名这三项关键信息&#xff08;…