【每日前端面经】2024-03-17

【每日前端面经】2024-03-17

本期重点 —— Promise

欢迎订阅我的前端面经专栏:每日前端面经

Tips:每日面经更新从 2-22 到 3-15 已有 23 篇,最近愈发觉得内容相似度高,并且理解程度不深  
于是临时停更面经,并将这些面经中的重难点以项目实战的方式展现出来供读者参阅本期项目地址:https://github.com/xxhls/02-write-promise

在线预览:02-write-promise

产生背景

在 Promise 出现前,对于多个异步请求,往往会产生回调地狱

const fs = require('fs');fs.readFile('./name.txt', 'utf-8', (err, data) => {fs.readFile(data, 'utf-8', (err, data) => {fs.readFile(data, 'utf-8', (err, data) => {console.log(data);});});
});

通过 Promise 可以有效解决以上问题

const fs = require('fs');new Promise((resolve, reject) => {fs.readFile('./name.txt', 'utf-8', (err, data) => {if (err) reject(err);resolve(data);}).then((data) => {return new Promise((resolve) => {fs.readFile(data, 'utf-8', (err, data) => {resolve(data);});});}).then((data) => {return new Promise((resolve) => {fs.readFile(data, 'utf-8', (err, data) => {resolve(data);});});});
})

相关 API

Promise.all()

接受一个 Promise 可迭代对象作为输入,并返回一个 Promise。当所有输入的 Promise 都被兑现时,返回的 Promise 也将被兑现,并返回一个包含所有兑现值的数组。如果输入的任何 Promise 被拒绝,则返回的 Promise 将被拒绝,并带有第一个被拒绝的原因

示例
const promise1 = Promise.resolve(3);
const promise2 = Promise.resolve(4);
const promise3 = new Promise((resolve, reject) => setTimeout(resolve, 100, 'foo'));Promise.all([promise1, promise2, promise3]).then((values) => console.log(values));// [3, 4, 'foo']
const promise1 = Promise.resolve(3);
const promise2 = Promise.reject(4);
const promise3 = new Promise((resolve, reject) => setTimeout(resolve, 100, 'foo'));Promise.all([promise1, promise2, promise3]).then((values) => console.log(values)).cache((reason) => console.log(reason));// 4
手写
function PromiseAll(promises: Array<Promise>) {// 总共 Promise 的个数const total = promises.length;// 完成的 Promise 的个数let i = 0;// 存储 Resolve 结果const result = [];return new Promise((resolve, reject) => {// 逐一添加处理函数promises.forEach((promise) => {promise.then((data) => {// 完成的 Promise 的个数加一i++;// Resolve 结果推入 result 中result.push(data);// 如果全部 Promise 都完成,就 Resolve 结果数组if (i === total) resolve(result);}).catch((reason) => {// 有一个 Promise 被拒绝直接 Reject 该原因reject(reason);});});});
}
Promise.allSettled()

将一个 Promise 可迭代对象作为输入,并返回一个单独的 Promise。当所有输入的 Promise 都已敲定时(包括传入空的可迭代对象时),返回的 Promise 将被兑现,并带有描述每个 Promise 结果的对象数组

示例
const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) =>setTimeout(reject, 100, 'foo'),
);
const promises = [promise1, promise2];Promise.allSettled(promises).then((results) =>results.forEach((result) => console.log(result.status)),
);// "fulfilled"
// "rejected"
手写
function PromiseAllSettled(promises: Array<Promise>) {// 总共 Promise 的个数const total = promises.length;// 完成的 Promise 的个数let i = 0;// 存储结果const result = [];return new Promise((resolve, reject) => {// 逐一添加处理函数promises.forEach((promise) => {promise.then((data) => {// 完成的 Promise 的个数加一i++;// Resolve 结果推入 result 中result.push("fulfilled");// 如果全部 Promise 都完成,就 Resolve 结果数组if (i === total) resolve(result);}).catch((reason) => {// 完成的 Promise 的个数加一i++;// Resolve 结果推入 result 中result.push("rejected");// 如果全部 Promise 都完成,就 Resolve 结果数组if (i === total) resolve(result);});});});
}
Promise.any()

将一个 Promise 可迭代对象作为输入,并返回一个 Promise。当输入的任何一个 Promise 兑现时,这个返回的 Promise 将会兑现,并返回第一个兑现的值。当所有输入 Promise 都被拒绝(包括传递了空的可迭代对象)时,它会以一个包含拒绝原因数组的 AggregateError 拒绝

示例
const promise1 = Promise.reject(0);
const promise2 = new Promise((resolve) => setTimeout(resolve, 100, 'quick'));
const promise3 = new Promise((resolve) => setTimeout(resolve, 500, 'slow'));const promises = [promise1, promise2, promise3];Promise.any(promises).then((value) => console.log(value));// "quick"
const promise1 = Promise.reject(0);
const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'quick'));
const promise3 = new Promise((resolve, reject) => setTimeout(reject, 500, 'slow'));const promises = [promise1, promise2, promise3];Promise.any(promises).catch((reasons) => console.log(reasons));// [0, "quick", "slow"]
手写
function PromiseAny(promises: Array<Promise>) {// 总共 Promise 的个数const total = promises.length;// 完成的 Promise 的个数let i = 0;// 存储拒绝结果const reasons = [];return new Promise((resolve, reject) => {// 逐一添加处理函数promises.forEach((promise) => {promise.then((data) => {// 如果一个 Promise 完成,就 Resolve 数据resolve(data);}).catch((reason) => {// 拒绝的 Promise 的个数加一i++;// Reject 结果推入 reasons 中reasons.push(reason);// 如果全部 Promise 都拒绝,就 Reject 结果数组if (i === total) reject(reasons);});});});
}
Promise.prototype.catch()

用于注册一个在 promise 被拒绝时调用的函数。它会立即返回一个等效的 Promise 对象,这可以允许你链式调用其他 promise 的方法

const promise1 = new Promise((resolve, reject) => {throw new Error('Uh-oh!');
});promise1.catch((error) => {console.error(error);
});
// Error: Uh-oh!
Promise.prototype.finally()

Promise 实例的 finally() 方法用于注册一个在 promise 敲定(兑现或拒绝)时调用的函数。它会立即返回一个等效的 Promise 对象,这可以允许你链式调用其他 promise 方法

function checkMail() {return new Promise((resolve, reject) => {if (Math.random() > 0.5) {resolve('Mail has arrived');} else {reject(new Error('Failed to arrive'));}});
}checkMail().then((mail) => {console.log(mail);}).catch((err) => {console.error(err);}).finally(() => {console.log('Experiment completed');});
Promise.race()

接受一个 promise 可迭代对象作为输入,并返回一个 Promise。这个返回的 promise 会随着第一个 promise 的敲定而敲定

示例
const promise1 = new Promise((resolve, reject) => {setTimeout(resolve, 500, 'one');
});const promise2 = new Promise((resolve, reject) => {setTimeout(resolve, 100, 'two');
});Promise.race([promise1, promise2]).then((value) => {console.log(value);// Both resolve, but promise2 is faster
});
// Expected output: "two"
手写
function PromiseRace(promises: Array<Promise>) {return new Promise((resolve, reject) => {// 逐一添加处理函数promises.forEach((promise) => {promise.then((data) => {// 如果一个 Promise 完成,就 Resolve 数据resolve(data);}).catch((reason) => {// 如果一个 Promise 完成,就 Reject 数据reject(data);});});});
}
Promise.reject()

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

function resolved(result) {console.log('Resolved');
}function rejected(result) {console.error(result);
}Promise.reject(new Error('fail')).then(resolved, rejected);
// Expected output: Error: fail
Promise.resolve()

将给定的值转换为一个 Promise。如果该值本身就是一个 Promise,那么该 Promise 将被返回;如果该值是一个 thenable 对象,Promise.resolve() 将调用其 then() 方法及其两个回调函数;否则,返回的 Promise 将会以该值兑现

该函数将嵌套的类 Promise 对象(例如,一个将被兑现为另一个 Promise 对象的 Promise 对象)展平,转化为单个 Promise 对象,其兑现值为一个非 thenable 值

const promise1 = Promise.resolve(123);promise1.then((value) => {console.log(value);// Expected output: 123
});
Promise.prototype.then()

最多接受两个参数:用于 Promise 兑现和拒绝情况的回调函数。它立即返回一个等效的 Promise 对象,允许你链接到其他 Promise 方法,从而实现链式调用

const promise1 = new Promise((resolve, reject) => {resolve('Success!');
});promise1.then((value) => {console.log(value);// Expected output: "Success!"
});

手写 Promise

const PENDING = Symbol('PENDING');
const FULLFILLED = Symbol('FULLFILLED');
const REJECTED = Symbol('REJECTED');enum Status {PENDING,FULLFILLED,REJECTED
}type Executor = (resolve: (value: any) => void, reject: (reason: any) => void) => void;class MyPromise {status: Status;data: any;reason: any;onResolvedCallbacks: Function[];onRejectedCallbacks: Function[];constructor(executor: Executor) {this.status = Status.PENDING;this.data = null;this.reason = null;this.onResolvedCallbacks = [];this.onRejectedCallbacks = [];const resolve = (data: any) => {console.log('resolve');if (this.status === Status.PENDING) {this.status = Status.FULLFILLED;this.data = data;this.onResolvedCallbacks.forEach(fn => fn());}};const reject = (reason: any) => {console.log('reject');if (this.status === Status.PENDING) {this.status = Status.REJECTED;this.reason = reason;this.onRejectedCallbacks.forEach(fn => fn());}};try {executor(resolve, reject);} catch (error) {reject(error);}}then(onFullfilled: (value: any) => any, onRejected: (reason: any) => any) {if (this.status === Status.FULLFILLED) {onFullfilled(this.data);} else if (this.status === Status.REJECTED) {onRejected(this.reason);} else if (this.status === Status.PENDING) {this.onResolvedCallbacks.push(() => {onFullfilled(this.data);});this.onRejectedCallbacks.push(() => {onRejected(this.reason);});}}
}console.log("测试 MyPromise");
new MyPromise((resolve, reject) => {setTimeout(() => {console.log('执行完成');resolve('success');}, 1000);
}).then((data) => {console.log('回调成功');console.log(data);
}, (reason) => {console.log(reason);
});new MyPromise((resolve, reject) => {setTimeout(() => {console.log('执行完成');reject('failure');}, 1000);
}).then((data) => {console.log('回调成功');console.log(data);
}, (reason) => {console.log('回调成功');console.log(reason);
});export default MyPromise;

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

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

相关文章

卷积神经网络算法原理(卷积层,卷积运算,填充,步幅,经过卷积运算后的特征图大小,池化层,最大池化,平均池化,经过池化层运算后的特征图大小)

文章目录 卷积神经网络算法原理(卷积层&#xff0c;卷积运算&#xff0c;填充&#xff0c;步幅&#xff0c;经过卷积运算后的特征图大小&#xff0c;池化层&#xff0c;最大池化&#xff0c;平均池化&#xff0c;经过池化层运算后的特征图大小)前言1、图像的本质1.1、灰度图1.2…

Java学习笔记(16)

常见算法 查找算法 查询某个元素是否存在 二分查找&#xff08;数组元素必须是有序的&#xff09; package exercise;public class exercise1 {public static void main(String[] args) {int[] arr {7, 23, 797, 23, 79, 81, 103, 127, 131, 147};System.out.println(binar…

实战Python Socket编程:开发多用户聊天应用

实战Python Socket编程&#xff1a;开发多用户聊天应用 Python Socket 编程概述什么是Socket编程&#xff1f;Socket编程的应用场景Socket编程的重要性基本概念 环境准备Python版本必要的库开发环境配置调试工具 基本Socket编程创建Socket绑定Socket到端口监听连接接受连接发送…

C语言经典面试题目(七)

1、C语言中如何进行内存对齐和字节对齐&#xff1f; 在C语言中&#xff0c;内存对齐和字节对齐是为了优化内存访问速度和提高系统性能而进行的一种策略。内存对齐是指数据在内存中的存放位置必须是某个值的倍数&#xff0c;通常是数据类型的大小。字节对齐是指数据在内存中的存…

24.第12届蓝桥杯省赛真题题解

A.空间&#xff08;100%&#xff09; 计算机存储单位计算 1TB2^10 GB 1GB2^10 MB 1MB2^10 KB 1KB2&10 B 1B8 bit(bit位二进制的最小的存储单位) #include <iostream> #include <cmath>using namespace std; //2^28B 2^2int main(){std::ios::sync_with_stdio…

【C语言入门】浮点型数据在内存中的存储

✨✨欢迎大家来到Celia的博客✨✨ &#x1f389;&#x1f389;创作不易&#xff0c;请点赞关注&#xff0c;多多支持哦&#x1f389;&#x1f389; 所属专栏&#xff1a;C语言 个人主页&#xff1a;Celias blog~ 目录 ​编辑 引言 引例 一、浮点型在内存中的存储方式 1.1 …

在idea中配置tomcat服务器,然后部署一个项日

1.下载tomcat Tomcat下载 点击右边的tomcat8 找到zip点击下载 下载完&#xff0c;解压到你想放置的路径下 2.配置环境变量 打开设置找到高级系统设置点击环境变量 点击新建&#xff0c;变量名输入&#xff1a;CATALINA_HOME&#xff0c;变量值就是Tomcat的安装路径&#x…

【QT+QGIS跨平台编译】之七十七:【QGIS_Gui跨平台编译】—【错误处理:字符串错误】

文章目录 一、字符串错误二、处理方法三、涉及到的文件一、字符串错误 常量中有换行符错误:(也有const char * 到 LPCWSTR 转换的错误) 二、处理方法 需要把对应的文档用记事本打开,另存为 “带有BOM的UTF-8” 三、涉及到的文件 src\gui\qgsadvanceddigitizingdockwidge…

智慧礼金:电子礼金薄,让礼薄更添智能,你确定不进来看看?

智慧礼金&#xff1a;电子礼金薄&#xff0c;让礼薄更添智能&#xff0c;你确定不进来看看&#xff1f; 一、重要声明二、相关介绍三、使用好处四、如何找到该小程序 随着科技的不断进步&#xff0c;传统的纸质礼金簿已经逐渐被电子化管理所取代。今天&#xff0c;我们要向大家…

Java解决完全二叉树的节点个数

Java解决完全二叉树的节点个数 01 题目 给你一棵 完全二叉树 的根节点 root &#xff0c;求出该树的节点个数。 完全二叉树 的定义如下&#xff1a;在完全二叉树中&#xff0c;除了最底层节点可能没填满外&#xff0c;其余每层节点数都达到最大值&#xff0c;并且最下面一层的…

1990-2022年各省全要素生产率数据(仅结果)

1990-2022年各省全要素生产率数据&#xff08;仅结果&#xff09; 1、时间&#xff1a;1990-2022年 2、指标&#xff1a;地区、年份、OLS、FE、RE、DGMM、SGMM、SFA1、SFA2、SFA3、SFA3D、TFE、非参数法 3、范围&#xff1a;31省 4、计算说明&#xff1a; 产出指标&#x…

【自动化测试】如何在jenkins中搭建allure

相信大家在做自动化测试过程中&#xff0c;都会用到自动化测试环境&#xff0c;目前最常见的就是通过容器化方式部署自动化测试环境&#xff0c;但对于一些测试小白&#xff0c;不是很会搭建持续集成环境&#xff0c;特别是从0-1的过程&#xff0c;需要自行搭建很多依赖环境&am…

奇数乘积(C语言)

一、运行结果&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff1b;int i 1;int j 3;//循环运算&#xff1b;while (j < 12){//运算&#xff1b;i i * j;//改变数值&#xff1b;j 2…

【2024-03-17】滴滴春招笔试两道编程题解

恭喜发现宝藏!搜索公众号【TechGuide】回复公司名,解锁更多新鲜好文和互联网大厂的笔经面经。 作者@TechGuide【全网同名】 订阅专栏: 【专享版】2024最新大厂笔试真题解析,错过必后悔的宝藏资源! 第一题:陨石坠落打击 题目描述 小盖正在模拟陨石对地质的危害。在小盖…

rt-thread之通讯协议modbus软件包的使用记录(lwip+modbus组合)

前言 使用freemodbus软件包使用网口通讯(sallwip)ip地址使用dhcp动态获取 软件包 相关宏定义 /*-----------------------------------------NET 宏定义-------------------------------------------*/#define RT_USING_SAL #define SAL_INTERNET_CHECK /* Docking with prot…

JavaScript内置对象

JavaScript内置对象 1.字符串对象 var s"abcdef";console.log(s.length);console.log(s.charAt(2));console.log(s.indexOf("c"));console.log(s.substring(0,4)); //substring(开始位置&#xff0c;结束位置) abcdconsole.log(s.substr(2,4)); //sub…

vue3依赖注入(provide 和 inject)

依赖注入&#xff08;provide 和 inject&#xff09;&#xff0c;解决Prop 逐级透传问题。跨多组件转递参数&#xff0c;避免使用Prop 逐级透传。 1. 父组件要为组件后代提供数据&#xff0c;需要使用到 provide() 函数&#xff1a; <script setup> import { provide,re…

前端框架vue的样式操作,以及vue提供的属性功能应用实战

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

【Linux】环境基础开发工具使用

目录 Linux软件管理器 yum 1.什么是软件包 2.查看软件包 3安装与卸载 vim-Linux编辑器 1.vim基础概念 2.vim的基础操作 命令模式基本操作 底层模式基本操作 3、其它模式 Linux编译器 gcc/g 1.如何进行编译 2.编译的四个过程 预处理(-E) 编译(-S) 汇编(-c) 链接…

python二级备考(2)-简单应用题

第1套 使用turtle库的turtle. right()函数和turtle.fd()函数绘制一个菱形&#xff0c;边长为200像素&#xff0c;4个内角度数为2个60度和2个120度 键盘输入一组人员的姓名、性别、年龄等信息&#xff0c;信息间采用空格分隔&#xff0c;每人一行&#xff0c;空行回车结束录入&a…