Promise原理、以及Promise.race、Promise.all、Promise.resolve、Promise.reject实现;

为了向那道光亮奔过去,他敢往深渊里跳;

于是今天朝着Promise的实现前进吧,写了四个小时,终于完结撒花;
我知道大家没有耐心,当然我也坐的腰疼,直接上代码,跟着我的注释一行行看过去,保证门清

const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"
// 提前封装好一个判断promise的 这里不用instanceof 因为有可能在我们的then的参数中,有可能是别人或者自己的promise
const isPromise = value => {return (!!value &&(typeof value === "object" || typeof value === "function") &&typeof value.then === "function")
}
class MyPromise {#state = PENDING // 当前执行状态#result = undefined // 当前结果值#handler = [] // 记录成功与失败回调的数组constructor(executor) {const resolve = value => {// resolve之后去改变当前状态为成功 与当前成功的值this.#changeState(value, FULFILLED)}const reject = reason => {// reject之后去改变当前状态为失败 与当前错误的值this.#changeState(reason, REJECTED)}try {// 这里直接执行参数中的函数executor(resolve, reject)} catch (error) {console.error(error)// 这里try catch 错误就走rejectreject(error)}}// 将传入的函数放到微队列中去执行#runMicroTask(runTask) {// 如果不兼容promiseif (typeof Promise === "function") {return Promise.resolve().then(runTask)}// MutationObserver兼容性更好if (typeof MutationObserver === "function") {const ob = new MutationObserver(runTask)const node = document.createTextNode("")ob.observe(node, { characterData: true })node.data = 1return}// 如果是node环境if (process.nextTick && typeof process.nextTick === "function") {process.nextTick(runTask)}} // 改变状态 保存此次的值 并且执行回调#changeState(result, state) {if (this.#state != PENDING) returnthis.#state = statethis.#result = resultthis.#run()}// 这里跑每次then后的回调#runOne(callback, resolve, reject) {// 这里主要是为了模拟微任务 都是伪代码this.#runMicroTask(() => {// 如果为函数if (typeof callback === "function") {try {// 拿到函数的返回值const data = callback(this.#result)// 如果是promise包括别人封装的promiseif (isPromise(data)) {console.log("data", data)// 如果是promise那就直接去执行.then 函数// 这里需要注意 这个resolve 是给下一个 所以这里这个resolve函数里带有上一次then返回来的值的!/* 可以看这里的注释来理解p.then(testMap.promiseTask, err => {console.log("第一次err err", err)throw "不好意思"}).then(res => {return new MyPromise(mySuc => {console.log("第二次", res)mySuc("MyPromise的值" + res)})},err => {console.log("第二次err err", err)})*/data.then(resolve, reject)} else {// 否则就自行resolve 把then(suc=>return '结果值') 就把这个data结果值给下一次调用的then传递过去resolve(data)}} catch (error) {// 不用解释了吧console.error(error)reject(error)}} else {// 如果不是函数 就直接执行resolveconst settled = this.#state === FULFILLED ? resolve : rejectsettled(this.#result)}})}#run() {if (this.#state === PENDING) return/*
把下面的注释拿上来 主要为了能一次看懂不来回跳动
这里做push主要是
const p = new MyPromise之后
p.then(res=>fn1(res))
p.then(res=>fn2(res))
记录两次 fn1 与fn2
当然如果不是链式调用其实两次的拿到的回调值都是一样的
*/while (this.#handler.length) {// 这里需要注意的是resolve 与reject用的是实际then函数中传递的resolve与reject 不是当前类中的resolveconst { onFulfilled, onRejected, resolve, reject } =this.#handler.shift()//  这里主要是为了简化代码 传递了此次this.#runOne(this.#state === FULFILLED ? onFulfilled : onRejected,resolve,reject)}}then(onFulfilled, onRejected) {return new MyPromise((resolve, reject) => {/*
这里做push主要是
const p = new MyPromise之后
p.then(res=>fn1(res))
p.then(res=>fn2(res))
记录两次 fn1 与fn2
当然如果不是链式调用其实两次的拿到的回调值都是一样的
*/this.#handler.push({onFulfilled,onRejected,resolve,reject,})this.#run()})}//catch方法的封装 catch 的话直接让它执行错误代码就好了 // 可不要以为有这样的代码比如Promise.catch 没有哈 都是new Promise的回调函数reject执行后的,所以这里只要让它有这个 reject方法就行了!catch(onRejected) {return this.then(undefined, onRejected)}//resolve方法的封装,凡是被static修饰的属性和方法都是静态方法和属性,只能被类名调用//不能被实例化对象调用.同时也不能被子类继承,换句话说它属于当前这个类的.static resolve(value) {//返回结果为Promise对象// 这里呢需要判断他是不是promise resolve中可能是个promise return new MyPromise((resolve, reject) => {if (isPromise(value)) {value.then(v => {resolve(v)},r => {reject(r)})} else {resolve(value)}})}//reject方法的封装 reject都是出错这种明确值,所以这里不需要判断 你给啥,我给下一个error给啥static reject(value) {return new MyPromise((resolve, reject) => {reject(value)})}//all方法的封装static all(promises) {const self = thisreturn new MyPromise((resolve, reject) => {let length = promises.length // 缓存一下有多少个promiselet count = 0 // 用于记录resolve的数量let values = new Array(length) // 用于存储resolve返回的值for (let i = 0; i < length; i++) {let promise = promises[i]// 判断数组的每一项,如果是promise,就进入then,不是就直接放进values数组中返回if (isPromise(promise)) {promise.then(res => {// 记录promise完成的数量count++// values存储每一个promise的resvalues[i] = res// 由于异步代码在最后执行,我们需要在then里面判断promise的完成数量,全部完成就resolve// 在for外面判断,是防止它全部都不是promise实例if (count === length) {resolve(values)}}).catch(err => {// 当有一个promise实例reject,我们就直接rejectreject(err)})} else {// 针对不是promise实例count++values[i] = promise}}// 当数据的所有项都不是promise实例,我们就在这判断多一次,然后resolveif (count === length) {resolve(values)}})}//race方法的封装static race(promises) {return new MyPromise((resolve, reject) => {const len = promises.lengthfor (let i = 0; i < len; i += 1) {const promise = promises[i]// 只要有一条成功则全部成功promise.then(res => {resolve(res)},error => {resolve(error)})}})}
}
window.MyPromise = MyPromiseconst test1 = new MyPromise(suc => {setTimeout(() => suc("成功 p"), 1001)
})
const test2 = new MyPromise((resolve, reject) => {setTimeout(() => {reject(3)}, 1000)
})
const test3 = new MyPromise(suc => {setTimeout(() => suc("成功 test3"), 1019)
})
MyPromise.all([test2, test1, test3]).then(res => {console.log("res all", res)}).catch(res => {console.log("error", res)})
MyPromise.race([test2, test1, test3]).then(res => {console.log("res race", res)}).catch(res => {console.log("error", res)})const catchTest = new MyPromise((resolve, reject) => {setTimeout(() => {reject("catch 测试")}, 1000)
}).catch(error => {console.error(error)
})const p = new MyPromise((resolve, reject) => {setTimeout(() => {resolve(3)}, 1000)
})const testMap = {promiseTask: res => {console.log("第一次 ===>", res)return new Promise(suc => {suc("promise方式的res", res)})},funcTask: res => {console.log("第一次 ===>", res)return res},// 直接穿透第一次resolve 或者reject 值到下一条then函数中otherTask: "其他",
}p.then(testMap.promiseTask, err => {console.log("第一次err err", err)throw "不好意思"
}).then(res => {return new MyPromise(mySuc => {console.log("第二次", res)mySuc("MyPromise的值" + res)})},err => {console.log("第二次err err", err)}).then(res => {console.log("第三次", res)return "第三次的值" + res},err => {console.log("第三次err err", err)}).then(res => {console.log("第四次", res)},err => {console.log("第四次err err", err)})

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

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

相关文章

python语法之数据类型

在python编程中&#xff0c;数据类型是一个重要的概念。 变量可以存储不同类型的数据&#xff0c;不同的类型可以做不同的事情。 Python在这些类别中默认内置了以下数据类型: 文本类型&#xff1a;str数值类型&#xff1a;int, float, complex序列类型&#xff1a;list, tup…

MySQL MVCC机制详解

MySQL MVCC机制详解 MVCC, 是Multi Version Concurrency Control的缩写&#xff0c;其含义是多版本并发控制。这一概念的提出是为了使得MySQL可以实现RC隔离级别和RR隔离级别。 这里回顾一下MySQL的事务&#xff0c; MySQL的隔离级别和各种隔离级别所存在的问题。 事务是由 …

立哥先进研发-API安全方案

项目背景&#xff1a;随着技术进步&#xff0c;很多优秀技术也被用在黑灰产之中&#xff0c;例如爬虫系统在票务系统中的滥用&#xff0c;尤其机票系统。机票爬虫们威力之大&#xff0c;让人叹为观止&#xff1a;多数订票网站&#xff0c;真实用户产生的不到10%&#xff0c;其浏…

【大语言模型】Docker部署清华大学ChatGLM3教程

官方地址&#xff1a;https://github.com/THUDM/ChatGLM3 1 将代码保存至本地 方法1&#xff1a; git clone https://github.com/THUDM/ChatGLM3 方法2&#xff1a; https://github.com/THUDM/ChatGLM3/archive/refs/heads/main.zip 2 创建Docker文件 注&#xff1a;请先…

人工智能与新能源电动车的融合——技术创新引领未来交通革命

人工智能与新能源电动车的融合——技术创新引领未来交通革命 摘要&#xff1a;本文探讨了人工智能与新能源电动车领域的技术融合&#xff0c;分析了其在智能驾驶、电池技术、充电设施等方面的应用与创新。文章指出&#xff0c;这两大技术的结合将重塑交通产业&#xff0c;为我…

Unity之NetCode多人网络游戏联机对战教程(8)--玩家位置同步

文章目录 前言添加相机玩家添加对应组件服务端权威&#xff08;server authoritative&#xff09;客户端权威&#xff08;client authoritative&#xff09;服务端同步位置阅读与理解PlayerTransformSync.csNetworkVariableUploadTransformSyncTransform 后话 前言 承接上篇&a…

【MybatisPlus】条件构造器、自定义SQL、Service接口

&#x1f40c;个人主页&#xff1a; &#x1f40c; 叶落闲庭 &#x1f4a8;我的专栏&#xff1a;&#x1f4a8; c语言 数据结构 javaEE 操作系统 Redis 石可破也&#xff0c;而不可夺坚&#xff1b;丹可磨也&#xff0c;而不可夺赤。 MybatisPlus 一、条件构造器1.1 基于QueryW…

Visual Studio Code 配置 C/C++ 开发环境的最佳实践(VSCode + Clangd + CMake)

Visual Studio Code 配置 C/C 开发环境的最佳实践(VSCode Clangd CMake) 知乎原文参考地址1 与 VSCode 官方文档配置 相比拥有的优势 Clangd 具有更优秀的性能&#xff0c;微软官方 Cpptools 的代码提示功能有明显延迟Clangd 提供更精准的「转到定义」、「重命名符号」、「…

【设计原则篇】聊聊开闭原则

开闭原则 其实就是对修改关闭&#xff0c;对拓展开放。 是什么 OCP&#xff08;Open/Closed Principle&#xff09;- 开闭原则。关于开发封闭原则&#xff0c;其核心的思想是&#xff1a;模块是可扩展的&#xff0c;而不可修改的。也就是说&#xff0c;对扩展是开放的&#xf…

学开发语言 求职互联网行业的未来发展

我喜欢回答各种各样的问题&#xff0c;自然也喜欢记录下自己的一些观点和看法。希望给朋友们多一点参考&#xff0c;也欢迎交流探讨。 提问&#xff1a; 自考本科&#xff0c;学的开发语言&#xff0c;问互联网行业求职和发展&#xff01; 作为一个资深码农&#xff0c;对这样…

php 插入排序算法实现

插入排序是一种简单直观的排序算法&#xff0c;它的基本思想是将一个数据序列分为有序区和无序区&#xff0c;每次从无序区选择一个元素插入到有序区的合适位置&#xff0c;直到整个序列有序为止 5, 3, 8, 2, 0, 1 HP中可以使用以下代码实现插入排序算法&#xff1a; functi…

import gradio时出现SyntaxError: future feature annotations is not defined解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

Word 插入的 Visio 图片显示为{EMBED Visio.Drawing.11} 解决方案

World中&#xff0c;如果我们插入了Visio图还用了Endnote&#xff0c; 就可能出现&#xff1a;{EMBED Visio.Drawing.11}问题 解决方案&#xff1a; 1.在相应的文字上右击&#xff0c;在出现的快捷菜单中单击“切换域代码”&#xff0c;一个一个的修复。 2.在菜单工具–>…

Elasticsearch--Python使用、Django/Flask集成

一、Python使用 from elasticsearch import Elasticsearchobj Elasticsearch() # 创建索引&#xff08;Index&#xff09; result obj.indices.create(indexuser, body{"userid":1,username:lqz},ignore400) # print(result) # 删除索引 # result obj.indices.de…

数据结构 | 图

最小生成树算法 Prime算法 算法思路&#xff1a;从已选顶点所关联的未选边中找出权重最小的边&#xff0c;并且生成树不存在环。 其中&#xff0c;已选顶点是构成最小生成树的结点&#xff0c;未选边是不属于生成树中的边。 例子&#xff1a; 第一步&#xff1a; 假设我们从顶…

C语言实现排序介绍

C语言学习都会学到排序算法&#xff0c;下面实现两个排序算法&#xff1a; #include <stdio.h>// 冒泡排序 void bubble_sort(int arr[], int n) {for (int i 0; i < n - 1; i) {for (int j 0; j < n - i - 1; j) {if (arr[j] > arr[j 1]) {int temp arr[j…

从0到0.01入门 Webpack| 002.精选 Webpack面试题

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

使用VSCode进行Python模块调试

使用VSCode进行Python模块调试 创建测试文件 创建文件test/a/b.py&#xff0c;且当前工作路径为test/ b.py文件内容&#xff1a; def cal(numa, numb):print(int(numa) int(numb))if __name__ "__main__":import sys# 判断系统参数长度是否为4且判断第2个参数是…

Sentinel底层原理(下)

1、概述 Sentinel的核心原理&#xff0c;也就是前面提到暗流涌动的SphU.entry(…)这行代码背后的逻辑。 Sentinel会为每个资源创建一个处理链条&#xff0c;就是一个责任链&#xff0c;第一次访问这个资源的时候创建&#xff0c;之后就一直复用&#xff0c;所以这个处理链条每…

打造全身视角的医院可视化能源监测管理平台,实现医院能源可视化管理

医院是大型公共建筑的一种&#xff0c;随着医院规模的不断扩大&#xff0c;医院能源消耗剧增&#xff0c;能源消耗居高不下。医院对于能源监管的需求也越来越高。医院建立一套能耗监测管理平台&#xff0c;对于降低医院能耗有着非常重要的作用。 医院能耗存在的问题 1、医院能…