假如面试官要你手写一个promise
promise
在开发中,经常需要用到promise,promise具有很多特性,这一次将对promise特性进行总结,并从零写一个promise。
步骤一
- Promise特点
- 1,创建时需要传递一个函数,否则会报错
- 2,会给传入的函数设置两个回调函数
- 3,刚创建的Promise对象状态是pending
class MyPromise {constructor(handle) {// 3,刚创建的Promise对象状态是pendingthis.status = "pending";// 1,创建时需要传递一个函数,否则会报错if (!this._isFunction(handle)) {throw new Error("请传入一个函数");}// 2,会给传入的函数设置两个回调函数handle(this._resolve.bind(this), this._reject.bind(this))}_resolve() {}_reject() {}_isFunction(fn) {return typeof fn === "function";}
}
步骤二
- Promise特点
- 4,状态一旦发生改变就不可再次改变
- 5,可以通过then来监听状态的改变
- 5.1,如果创建监听时,状态已经改变,立即执行监听回调
- 5.2,如果创建监听时,状态未改变,会等状态改变后执行
- 5.3,同一promise对象可以添加多个then监听,状态改变时按照注册顺序依次执行
// 定义常量保存对象的状态
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";class MyPromise {constructor(handle) {// 3,刚创建的Promise对象状态是pendingthis.status = PENDING;// 成功回调的值this.value = undefined;// 失败回调的值this.reason = undefined;// 注册的成功回调this.onResolvedCallbacks = [];// 注册的失败回调this.onRejectedCallbacks = [];// 1,创建时需要传递一个函数,否则会报错if (!this._isFunction(handle)) {throw new Error("请传入一个函数");}// 2,会给传入的函数设置两个回调函数handle(this._resolve.bind(this), this._reject.bind(this))}_resolve(value) {// 4,状态一旦发生改变就不可再次改变if (this.status === PENDING) {this.status = FULFILLED;this.value = value;// 5.3,同一promise对象可以添加多个then监听,状态改变时按照注册顺序依次执行this.onResolvedCallbacks.forEach(fn => fn(this.value));}}_reject(reason) {// 4,状态一旦发生改变就不可再次改变if (this.status === PENDING) {this.status = REJECTED;this.reason = reason;// 5.3,同一promise对象可以添加多个then监听,状态改变时按照注册顺序依次执行this.onRejectedCallbacks.forEach(fn => fn(this.reason));}}then(onResolved, onRejected) {// 判断有没有传入成功的回调if (this._isFunction(onResolved)) {// 5.1,如果创建监听时,状态已经改变,立即执行监听回调if (this.status === FULFILLED) {onResolved(this.value);}}// 判断有没有传入失败的回调if (this._isFunction(onRejected)) {// 5.1,如果创建监听时,状态已经改变,立即执行监听回调if (this.status === REJECTED) {onRejected(this.reason);}}// 5.2,如果创建监听时,状态未改变,会等状态改变后执行if (this.status === PENDING) {if (this._isFunction(onResolved)) {this.onResolvedCallbacks.push(onResolved);}if (this._isFunction(onRejected)) {this.onRejectedCallbacks.push(onRejected);}}}_isFunction(fn) {return typeof fn === "function";}
}
详解then方法
- 接收两个参数:成功回调,失败回调
- 如果promise失败了,但是没有注册失败监听,就会报错
- then方法每次执行完毕都会返回一个新的Promise对象
- 如果then方法只有成功回调
- 则它返回的promise的状态会继承当前promise的状态。
- 如果当前promise的状态为成功:新promise的值为当前then的成功回调的返回值。
- 如果当前promise的状态为失败:新的promise没有失败监听,则会报错
- 如果then方法同时包含成功回调、失败回调
- 则它返回的promise的状态都为成功,且值为成功或者失败回调的返回值。
- 如果then方法只有成功回调
- 回调函数的返回值
- 如果then方法的成功/失败回调返回的是promise对象
- 则then方法返回的新的promise对象的状态由新promise的内部决定。
- 且值为新promise的内resolve/reject函数传递的参数。
- 如果then方法的成功/失败回调返回的是普通数据类型
- 则then方法返回的新的promise对象的状态都为成功。
- 且值为成功/失败回调的返回值,即都会传递给新的promise对象成功的回调。
- 如果then方法的成功/失败回调没有返回值
- 同返回普通数据类型
- 如果then方法的成功/失败回调返回的是promise对象
- 失败回调函数
- 可以捕获上一个promise对象的then方法中成功回调函数执行时的异常
参考 前端进阶面试题详细解答
then(onResolved, onRejected) {return new MyPromise((nextResolve, nextReject) => {// 1.判断有没有传入成功的回调if (this._isFunction(onResolved)) {// 2.判断当前的状态是否是成功状态if (this.status === FULFILLED) {try {// 拿到上一个promise成功回调执行的结果let result = onResolved(this.value);// console.log("result", result);// 判断执行的结果是否是一个promise对象if (result instanceof MyPromise) {result.then(nextResolve, nextReject);} else {// 将上一个promise成功回调执行的结果传递给下一个promise成功的回调nextResolve(result);}} catch (e) {nextReject(e);}}}// 1.判断有没有传入失败的回调// if(this._isFunction(onRejected)){try {// 2.判断当前的状态是否是失败状态if (this.status === REJECTED) {let result = onRejected(this.reason);if (result instanceof MyPromise) {result.then(nextResolve, nextReject);} else {nextResolve(result);}}} catch (e) {nextReject(e);}// }// 2.判断当前的状态是否是默认状态if (this.status === PENDING) {if (this._isFunction(onResolved)) {// this.onResolvedCallback = onResolved;this.onResolvedCallbacks.push(() => {try {let result = onResolved(this.value);if (result instanceof MyPromise) {result.then(nextResolve, nextReject);} else {nextResolve(result);}} catch (e) {nextReject(e);}});}// if(this._isFunction(onRejected)){// this.onRejectedCallback = onRejected;this.onRejectedCallbacks.push(() => {try {let result = onRejected(this.reason);if (result instanceof MyPromise) {result.then(nextResolve, nextReject);} else {nextResolve(result);nextReject();}} catch (e) {nextReject(e);}});// }}});
}
详解catch方法
- 其实是then方法的失败回调函数的语法糖
- 如果需要同时使用then和catch方法,必须使用链式编程,不然会报错
- 可以捕获上一个promise对象的then方法中成功回调函数执行时的异常
catch(onRejected) {return this.then(undefined, onRejected);
}
为啥使用catch时最好使用链式编程
- 因为then方法只有成功回调,所以p2的状态会继承p1
- 又因为p2的状态为失败,且没有对p2进行失败监听,所以报错
let p1 = new Promise(function (resolve, reject) {// resolve();reject();
});
let p2 = p1.then(function () {console.log("成功");
});
p1.catch(function () {console.log("失败1");
});
Promise.all()
- Promise.all(params)特点
- 参数为一个数组,且数组元素为promise类型数据
- 返回值为一个promise,
- 如果所有promise都执行成功
- 返回值为所有promise都成功时返回的结果的集合
- 如果有一个promise执行失败了,则返回失败的promise
- 如果所有promise都执行成功
static all(list){return new MyPromise(function (resolve, reject) {let arr = [];let count = 0;for(let i = 0; i < list.length; i++){let p = list[i];p.then(function (value) {// arr.push(value); 注意不要这样写,会导致结果顺序不对arr[i] = valuecount++;if(list.length === count){resolve(arr);}}).catch(function (e) {reject(e);});}});
}
Promise.race()
- Promise.race(params)特点
- 参数为一个数组,且数组元素为promise类型数据
- 返回值为一个promise,且返回值为第一个成功或者失败的promise的值
static race(list){return new MyPromise(function (resolve, reject) {for(let p of list){p.then(function (value) {resolve(value);}).catch(function (e) {reject(e);});}})
}
相关文章:
假如面试官要你手写一个promise
promise 在开发中,经常需要用到promise,promise具有很多特性,这一次将对promise特性进行总结,并从零写一个promise。 步骤一 Promise特点 1,创建时需要传递一个函数,否则会报错2,会给传入的函…...
【leetcode】寻找重复数
题目链接:寻找重复数https://leetcode.cn/problems/find-the-duplicate-number/ 方法一:快慢指针 因为只有一个数字是重复的,且一个数字正好对应一个唯一的下标,所以可以将数组抽象为一个链表,假定数组为{1,2,3,4,5,…...
LeetCode 1247. Minimum Swaps to Make Strings Equal【数学,贪心,字符串】
本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章…...
pid控制加热算法,附代码仓库
1、该项目层次化结构清晰,代码框架耦合度低,可复用性、可移植性强。 2、功能代码与底层硬件无直接关联,无需更改上层应用逻辑,只需更改接口文件,即可移植到不同的硬件平台; 3、使用lwrb开源组件、pid开源算…...
一文看懂预训练和自训练模型
说到预训练模型,不得不提迁移学习了,由于很多数据不是标签数据,人工标注非常耗时,神经网络在很多场景下受到了限制。但是迁移学习和自学习的出现,在一定程度上缓解甚至解决了这个问题。我们可以在标签丰富的场景下进行…...
(五十四)大白话索引的页存储物理结构,是如何用B+树来实现的?.md
上一次我们给大家说了主键索引的目录结构,只要在一个主键索引里包含每个数据页跟他最小主键值,就可以组成一个索引目录,然后后续你查询主键值,就可以在目录里二分查找直接定位到那条数据所属的数据页,接着到数据页里二…...
前端Vue代码风格指南
一、命名规范 市面上常用的命名规范: camelCase(小驼峰式命名法 —— 首字母小写) PascalCase(大驼峰式命名法 —— 首字母大写) kebab-case(短横线连接式) Snake(下划线连接式&…...
「TCG 规范解读」基础设施架构和协议 (2)
可信计算组织(Ttrusted Computing Group,TCG)是一个非盈利的工业标准组织,它的宗旨是加强在相异计算机平台上的计算环境的安全性。TCG于2003年春成立,并采纳了由可信计算平台联盟(the Trusted Computing Platform Alli…...
NodeJs 中的 HTML 模板
💂 个人网站:【海拥】【摸鱼游戏】【神级源码资源网】🤟 前端学习课程:👉【28个案例趣学前端】【400个JS面试题】💅 想寻找共同学习交流、摸鱼划水的小伙伴,请点击【摸鱼学习交流群】 HTML 模板是一种允许我…...
3.ffmpeg命令行环境搭建、ffmpeg命令行初步了解
在上章,我们讲过: ffmpeg.exe: 主要用于转码或者剪切的应用程序, 也可以从url/现场音频/视频源抓取输入源ffplay.exe: 主要用于播放视频的应用程序,该应用程序源码是开源的,我们后面章节会去源码分析ffprobe.exe: 主要用于分析视频码流的应用程序, 可以获取媒体文件的详细信息,…...
Kubernetes初始化容器
初始化容器 之前了解了容器的健康检查的两个探针:liveness probe(存活探针)和readiness probe(可读性探针)的使用方法,我们说在这两个探针是可以影响容器的生命周期的,包括我们之前提到的容器的…...
leetcode: Swapping Nodes in a Linked List
leetcode: Swapping Nodes in a Linked List1. 题目描述2. 题目解答3. 总结1. 题目描述 You are given the head of a linked list, and an integer k.Return the head of the linked list after swapping the values of the kth node from the beginning and the kth node f…...
Nydus 在约苗平台的容器镜像加速实践
文 | 向申 约苗平台运维工程师 关注云原生领域 本文字数 9574阅读时间24分钟 本文是来自向申同学的分享,介绍了其在 K8s 生产环境集群部署 Nydus 的相关实践。 Nydus 是蚂蚁集团,阿里云和字节等共建的开源容器镜像加速项目,是 CNCF Dragon…...
企业对不同形态CRM系统价格需求不同
很多企业在选型时关心CRM客户管理系统的价格,有人对CRM的价格完全没有概念,也有的人先问价格再看其他。CRM价格在系统选型中到底有多重要?不同类型CRM系统的价格是否有所不同? CRM的不同产品形态也会影响价格 通常情况下&#x…...
「JVM 高效并发」线程安全
面向过程编程,把数据和过程分别作为独立的部分考虑,数据代表问题空间中的客体,程序代码则用于处理这些数据;面向对象编程,把数据和行为都看做对象的一部分,以符合现实世界的思维方式来编写和组织程序&#…...
微信扫码登录
一、准备工作 微信开发者平台:https://open.weixin.qq.com 1、注册 2、邮箱激活 3、完善开发者资料 4、开发者资质认证:仅能企业注册(后面提供学习的使用渠道)准备营业执照,1-2个工作日审批、300元 5、创建网站应用&…...
Unity协程的简单应用
Unity协程是一种特殊的函数,可以让你在Unity中创建一种类似于多线程的异步操作。它可以在需要等待某个操作完成时,暂停执行当前代码,等待某个条件满足后再继续执行。 在一般情况下 unity中调用函数时,函数将运行到完成状态&#x…...
LeetCode 1250. Check If It Is a Good Array【数论】
本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章…...
ETHDenver 2023
ETHDenver是全球最大、持续时间最长的以太坊活动之一,今年的活动定于2月24日至3月5日在美国科罗拉多州丹佛市盛大举行。这次活动将面向以太坊和其他区块链协议爱好者、设计者和开发人员。Moonbeam作为ETHDenver 2023的Meta赞助商,将在本次活动中展示令人…...
React架构演变
老版React架构 React 16之前的架构 其实就分为两个部分: Reconciler协调器Render渲染器 Reconciler协调器负责本次更新有什么组件需要被渲染,diff算法就发生在这个步骤中,在diff算法中会将上次更新的组件和本次更新的组件做一个对比&…...
Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...
第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...
uniapp 字符包含的相关方法
在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...
第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10+pip3.10)
第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10pip3.10) 一:前言二:安装编译依赖二:安装Python3.10三:安装PIP3.10四:安装Paddlepaddle基础框架4.1…...
聚六亚甲基单胍盐酸盐市场深度解析:现状、挑战与机遇
根据 QYResearch 发布的市场报告显示,全球市场规模预计在 2031 年达到 9848 万美元,2025 - 2031 年期间年复合增长率(CAGR)为 3.7%。在竞争格局上,市场集中度较高,2024 年全球前十强厂商占据约 74.0% 的市场…...
从零手写Java版本的LSM Tree (一):LSM Tree 概述
🔥 推荐一个高质量的Java LSM Tree开源项目! https://github.com/brianxiadong/java-lsm-tree java-lsm-tree 是一个从零实现的Log-Structured Merge Tree,专为高并发写入场景设计。 核心亮点: ⚡ 极致性能:写入速度超…...
【记录坑点问题】IDEA运行:maven-resources-production:XX: OOM: Java heap space
问题:IDEA出现maven-resources-production:operation-service: java.lang.OutOfMemoryError: Java heap space 解决方案:将编译的堆内存增加一点 位置:设置setting-》构建菜单build-》编译器Complier...
