JavaScript实现Promise

第一步:编写constructor构造方法

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';class MyPromise {#state = PENDING;#result = undefined;constructor(executor) {const resolve = (data) => {this.#changeState(FULFILLED, data)}const reject = (reason) => {this.#changeState(REJECTED, reason)}executor(resolve, reject)}#changeState(state, result) {if (this.#state === PENDING) return; // 状态一旦定下来,就不能再改变了this.#state = state;this.#result = result;}
}const p = new MyPromise((resolve, reject) => {resolve(1);reject(123); // 这里调用,不会起到任何作用
})console.log(p);

注意:状态一旦确定,就不能再改变的promise的状态

第二步:考虑异常情况

//用try catch包裹executor方法处理
//...try {executor(resolve, reject)} catch (err) {reject(err)}
//...const p = new MyPromise((resolve, reject) => {throw 123;
})

但是这种处理方式,对于异步的报错,没有办法

const p = new MyPromise((resolve, reject) => {setTimeout(() => {throw 123;}, 1000);
})

这个异步抛异常的问题是没法解决的,官方的实现也存在这个问题,异步抛异常是无法改变promise状态(没有执行changeState方法)

第三步:实现then方法(比较复杂)

一般会这么调用then方法

const p = new MyPromise((resolve, reject) => {setTimeout(() => {resolve("ok");}, 1000);
})//这个方法会优先于上面的setTimeout方法执行,所以会被记录,然后在setTimeout后执行
p.then(res => {console.log(res + 1);},err => {console.log(err);}
)p.then(res => {console.log(res + 2);},err => {console.log(err);}
)

图解:在调用then方法的时候,记录当前的参数 ,等setTimeout时间一到,就去执行#run方法
在这里插入图片描述

此时实现的MyPromise的代码如下

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';class MyPromise {#state = PENDING;#result = undefined;#handlers = []; //记录多少个then的回调方法constructor(executor) {const resolve = (data) => {this.#changeState(FULFILLED, data)}const reject = (reason) => {this.#changeState(REJECTED, reason)}try {executor(resolve, reject)} catch (err) {reject(err)}}//状态改变时,调用这个方法#changeState(state, result) {if (this.#state !== PENDING) return; // 状态一旦定下来,就不能再改变了this.#state = state;this.#result = result;this.#run();}//执行handlers里面的方法,handlers的方法是调用then时,所记录的方法#run() {if (this.#state === PENDING) return;while (this.#handlers.length) {const { onFulfilled, onRejected, resolve, reject } = this.#handlers.shift();if (this.#state === FULFILLED) {if (typeof onFulfilled === 'function') {onFulfilled(this.#result);}} else {if (typeof onRejected === 'function') {onRejected(this.#result);}}}}then(onFulfilled, onRejected) {return new MyPromise((resolve, reject) => {//记录到#handlers这个变量中,等setTimeout时间一到,就去执行onFulfilled或者onRejected方法//resolve和reject是返回的一个新的promise的参数,这个新的promise用户链式调用(下面会写)this.#handlers.push({onFulfilled,onRejected,resolve,reject})this.#run();})}
}const p = new MyPromise((resolve, reject) => {setTimeout(() => {resolve("ok");}, 1000);
})//这个方法会优先于上面的setTimeout方法执行,所以会被记录到setTimeout后执行
p.then(res => {console.log(res + 1);},err => {console.log(err);}
)p.then(res => {console.log(res + 2);},err => {console.log(err);}
)

第四步:then的链式调用(比较复杂)

返回的是一个新的promise对象(以前面试有被问道,我回答错了)

//1.编写constructor构造方法,需要考虑状态一旦确定,就不能再改变的因素
const p = new MyPromise((resolve, reject) => {setTimeout(() => {resolve(1);}, 1000);
})//这个方法会优先于上面的setTimeout方法执行,所以会被记录到setTimeout后执行
p.then(res => {console.log(res); //1return res + 1},err => {console.log(err);}
).then(res => {console.log(res); //2
}, err => {console.log(err);
})
// 手写Promiseconst PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';class MyPromise {#state = PENDING;#result = undefined;#handlers = [];constructor(executor) {const resolve = (data) => {this.#changeState(FULFILLED, data)}const reject = (reason) => {this.#changeState(REJECTED, reason)}try {executor(resolve, reject)} catch (err) {reject(err)}}#changeState(state, result) {if (this.#state !== PENDING) return; // 状态一旦定下来,就不能再改变了this.#state = state;this.#result = result;this.#run();}//判断是不是Promise类型#isPromiseLike(value) {if (value !== null && (typeof value === 'object' || typeof value.then === 'function')) {return typeof value.then === 'function';}return false;}//微队列#runMicroTask(func) {//node环境中if (typeof process === 'object' && typeof process.nextTick === 'function') {process.nextTick(func);}//浏览器环境中else if (typeof MutationObserver === 'function') {const observer = new MutationObserver(func); //观察器const p = document.createTextNode('1');observer.observe(p, { characterData: true }); //当p节点发生改变的时候,执行funcp.data = '2';} else {setTimeout(func, 0);}}#runOne(callback, resolve, reject) {this.#runMicroTask(() => {//如果传来的不是function类型if (typeof callback !== 'function') {const settled = this.#state === FULFILLED ? resolve : reject;settled(this.#result); //将把当前的promise状态,传给下一个promisereturn;}//如果传来的是function类型try {const data = callback(this.#result);if (this.#isPromiseLike(data)) {data.then(resolve, reject);} else {reject(data);}} catch (err) {reject(err)}})}#run() {if (this.#state === PENDING) return;while (this.#handlers.length) {const { onFulfilled, onRejected, resolve, reject } = this.#handlers.shift();if (this.#state === FULFILLED) {this.#runOne(onFulfilled, resolve, reject)} else {this.#runOne(onRejected, resolve, reject)}}}then(onFulfilled, onRejected) {return new MyPromise((resolve, reject) => {this.#handlers.push({onFulfilled,onRejected,resolve,reject})this.#run();})}
}//1.编写constructor构造方法,需要考虑状态一旦确定,就不能再改变的因素
const p = new MyPromise((resolve, reject) => {setTimeout(() => {resolve(1);}, 1000);
})//这个方法会优先于上面的setTimeout方法执行,所以会被记录到setTimeout的定时时间到后执行
p.then(null, //如果不是一个函数,就延续上一个promise的状态err => {console.log(err);}).then(data => {console.log(data); //1},err => {console.log(err);})

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

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

相关文章

物理 + 人工智能 = 2024年诺贝尔物理学奖

💓 博客主页:倔强的石头的CSDN主页 📝Gitee主页:倔强的石头的gitee主页 ⏩ 文章专栏:《热点时事》 期待您的关注 目录 引言 一、机器学习与神经网络的发展前景 二、机器学习和神经网络的研究与传统物理学的关系 结…

C++:异常

1. 异常的概念 C语言主要通过错误码的方式处理错误,错误码本质上就是对错误信息进行分类编号,拿到错误码以后还要去查询错误信息,比较麻烦。异常时抛出一个对象,这个对象可以涵盖更全面的信息。 异常处理机制允许程序中独立开发的…

南京邮电大学算法设计-二叉树先序遍历算法动态演示

二叉树先序遍历算法动态演示 一、课题内容和要求 (1)实验目的: 本实验通过手动输入二叉树结点信息,构建相应的二叉树,并通过图形化界面动态演示先序遍历算法的过程。通过本次实验,我可以深入理解二叉树的数据结构、先序遍历算法…

【开源免费】基于Vue和SpringBoot的在线考试系统(附论文)

本文项目编号 T 624 ,文末自助获取源码 \color{red}{T624,文末自助获取源码} T624,文末自助获取源码 网络的广泛应用给生活带来了十分的便利。所以把在线考试管理与现在网络相结合,利用java技术建设在线考试系统,实现…

高阶C语言之六:程序环境和预处理

本文介绍程序的环境,在Linux下对编译链接理解,较为简短,着重在于编译的步骤。 C的环境 在ANSI C(标准C语言)的任何一种实现中,存在两个不同的环境。 翻译环境:在这个环境中,源代码…

HarmonyOs鸿蒙开发实战(10)=>状态管理-对象数组的属性数据变更刷新UI,基于@Observed 和@ObjectLink装饰器

1.条件:基于HarmonyOs5.0.0版本. 2.功能要求:横向列表中每个景点的名称(eg: 第二项 “灵隐寺” ), 在通过天气接口拿到对应天气后,拼接到名称后面 > 变成(“灵隐寺” 天气)) 3.老规矩先看…

快速上手Mybatis Plus并速通MybatisPlus所有知识点

目录 一、简介 1.1 概况 1.2 特性 二、快速入门 1.建表 2.引依赖 3.application.ymal文件 4.定义mapper继承BaseMapper 5.总结 三、Mybatis Plus的使用 1.常见注解 1.1 TableName 1.2 TableId 1.3 TableField 2.常见配置 3.BaseMapper的基础CRUD方法 4.Wrapper…

使用代理解决前端跨域问题详解

目录 前言1. 什么是跨域问题?1.1 同源策略的定义1.2 跨域问题的表现 2. 解决跨域问题的常见方法3. 在 Vite 中配置代理解决跨域问题3.1 环境准备3.2 配置代理3.2.1 配置基础路径3.2.2 配置 Vite 代理3.2.3 参数解释 3.3 验证代理功能 4. 深入分析与注意事项4.1 代理…

使用MaxKB搭建知识库问答系统并接入个人网站(halo)

首发地址(欢迎大家访问):使用MaxKB搭建知识库问答系统并接入个人网站 前言 从OpenAI推出ChatGPT到现在,大模型已经渗透到各行各业,大模型也逐渐趋于平民化;从最开始对其理解、生成、强大的知识积累的惊叹&…

查看台式机主机支持的最大分辨率 | 显卡和显示器

通过检查显卡规格和型号,确认主机支持最大分辨率。 方法1:设置 在设置 -> 系统 -> 屏幕 及其内的高级显示设置 设置 -> 显示 方法2:cmd 在运行中输入“devmgmt.msc”,进入设备管理器界面,点击展开“显示适配…

若依权限控制

springbootvue2项目中的权限控制(若依项目) 步骤: 1.登录管理员账号,为普通用户增加权限按钮 绿色部分为权限控制字符 2.在后端对应的方法上增加权限控制(这里以删除操作为例):PreAuthorize(“ss.hasPermi(‘area:store:remove’)”) 3.在前端对应的按钮上增加权限控制:v-ha…

5G的SUCI、SUPI、5G-GUTI使用场景及关系

使用场景(来源于对23.501、23.502、33.501、23.003的理解) 1、UE初始注册时,根据HN Public Key把SUPI加密成SUCI,并发送初始注册请求 2、AMF转发SUCI给AUSF和UDM进行认证,并获取解密后的SUPI 3、AMF根据SUPI生成一个5G-GUTI,并保…

本地部署 excalidraw

本地部署 excalidraw 0. 引言1. 本地部署 excalidraw2. 访问 excalidraw 0. 引言 Excalidraw 编辑器是一款开源虚拟手绘白板,支持协作且端到端加密。 1. 本地部署 excalidraw git clone https://github.com/excalidraw/excalidraw.git; cd excalidrawvi docker-c…

企业数字化转型的战略指南:物联网与微服务架构的深度融合及应用解析

新时代下的企业数字化转型挑战与机遇 在当前全球经济和技术迅猛发展的背景下,企业数字化转型成为保持竞争力和创新的关键战略。物联网(IoT) 的兴起为企业提供了无数新的数据来源和运营模式,然而,如何有效整合这些数据…

vue3+vant实现弹幕循环播放~

1、效果图 <!-- 弹幕 --> <div style"height: 88px"><van-barragev-model"list"duration"5000":rows"rows":gap"gap":loop"loop"style"--move-distance: -345px" ><div class&quo…

字母异位词分组(java)

题目描述 给你一个字符串数组&#xff0c;请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词 是由重新排列源单词的所有字母得到的一个新单shilie 示例 1: 输入: strs ["eat", "tea", "tan", "ate", "n…

解决ValueError: Custom function inv is not defined in `extra_sympy_mappings`.

一、报错问题 ValueError: Custom function inv is not defined in extra_sympy_mappings. You can define it with, e.g., model.set_params(extra_sympy_mappings{inv: lambda x: 1/x}), where lambda x: 1/x is a valid SymPy function defining the operator. You can als…

深度学习基础练习:代码复现transformer重难点

2024/11/10-2024/11/18: 主要对transformer一些比较难理解的点做了一些整理&#xff0c;希望对读者有所帮助。 前置知识&#xff1a; 深度学习基础练习&#xff1a;从pytorch API出发复现LSTM与LSTMP-CSDN博客 【神经网络】学习笔记十四——Seq2Seq模型-CSDN博客 【官方双语】一…

GIS与Web开发结合的产物:WebGIS

WebGIS&#xff0c;其实是利用Web开发技术结合地理信息系统&#xff08;GIS&#xff09;的产物&#xff0c;它是一种通过Internet实现GIS交互操作和服务的最佳途径。 WebGIS通过图形化界面直观地呈现地理信息和特定数据&#xff0c;具有可扩展性和跨平台性。 它提供交互性&am…

PAT甲级 1071 Speech Patterns(25)

&#x1f7e0; 题目大意&#x1f7e2; 思路分析&#x1f535; 代码改进&#x1f7e4; 总结提炼 原题链接 &#x1f7e0; 题目大意 给定一串字符串&#xff0c;要求找出字符串中出现次数最多的单词。 输入 输入一行字符串&#xff0c;字符串长度不超过1048576&#xff0c;所有…