当前位置: 首页 > news >正文

面试手写第二期 Promsie相关

文章目录

  • 一. 手写实现PromiseA+规范
  • 二. Promise.all实现
  • 三. Promise.race实现
  • 四. Promise.allsettled实现
  • 六. Promise.any实现
  • 六. 如何实现 Promise.map,限制 Promise 并发数
  • 七. 实现函数 promisify,把回调函数改成 promise 形式
  • 八. 并发请求控制

一. 手写实现PromiseA+规范

class Mypromise {state = 'pending'; // 状态 'pending' 'fulfilled' 'rejected'value = undefined; // 成功后的值reason = undefined; //// 如果要是 setTimeout改变状态,就先将回调保存起来resolveCallbacks = []; // .then的时候 状态为pending时,存储回调rejectCallbacks = [];constructor(fn) {const resolveHandler = (value) => {if (this.state === 'pending') {this.state = 'fulfilled';this.value = value;console.log(this.resolveCallbacks);// 状态初始为pending,然后变化后在这里执行 fnthis.resolveCallbacks.forEach((fn) => fn(this.value));}};const rejectHandler = (reason) => {if (this.state === 'pending') {this.state = 'rejected';this.reason = reason;this.rejectCallbacks.forEach((fn) => fn(this.reason));}};try {fn(resolveHandler, rejectHandler);} catch (err) {rejectHandler(err);}}then(fn1, fn2) {fn1 = typeof fn1 === 'function' ? fn1 : (v) => v;fn2 = typeof fn2 === 'function' ? fn2 : (err) => err;// 状态还没有发生改变,存储fn1,fn2if (this.state === 'pending') {const p1 = new Mypromise((resolve, reject) => {// 保存函数// 当状态改变为fulfilled的时候,执行下面的回调this.resolveCallbacks.push(() => {try {const newValue = fn1(this.value);resolve(newValue); // p1.value} catch (error) {reject(error);}});this.rejectCallbacks.push(() => {try {const newRerson = fn2(this.reason);reject(newRerson); // p1.reason} catch (error) {reject(error);}});});return p1;}// 状态已经改变,直接执行if (this.state === 'fulfilled') {// 执行完then 返回一个新的promiseconst p1 = new Mypromise((resolve, reject) => {try {// this.value == resolve(value)里面传的值const newValue = fn1(this.value);// 返回新的值console.log(newValue);resolve(newValue);} catch (error) {reject(error);}});return p1;}if (this.state === 'rejected') {const p1 = new Mypromise((resolve, reject) => {try {const newReason = fn2(this.reason);reject(newReason);} catch (error) {reject(error);}});return p1;}}// .catch 是 then的语法糖catch(fn) {return this.then(null, fn);}finally(fn) {return this.then((value) => {return Mypromise.resolve(fn()).then(() => value)}, err => {return Mypromise.resolve(fn()).then(() => throw err)})}
}// MyPromise的静态方法
Mypromise.resolve = function (value) {return new Mypromise((resolve, reject) => resolve(value));
};Mypromise.reject = function (value) {return new Mypromise((resolve, reject) => reject(reason));
};

二. Promise.all实现

Mypromise.all = function (promiseList = []) {const p1 = new Mypromise((resolve, reject) => {const result = [];const length = promiseList.length;let resolveCount = 0;promiseList.forEach((p, index) => {p.then((data) => {result[index] = data;// resolveCount 必须在 then 里面做 ++// 不能用indexresolveCount++;if (resolveCount === length) {resolve(result);}}).catch((err) => {reject(err);});});});return p1;
};

三. Promise.race实现

Mypromise.race = function (promiseList = []) {let resolved = false; // 标记const p1 = new Promise((resolve, reject) => {promiseList.forEach((p) => {p.then((data) => {if (!resolved) {resolve(data);resolved = true;}}).catch((err) => {reject(err);});});});return p1;
};

四. Promise.allsettled实现

Mypromise.allSettled = function (promiseList = []) {return new Promise((resolve, reject) => {const res = [],len = promiseList.length,count = len;promiseList.forEach((item, index) => {item.then((res) => {res[index] = { status: 'fulfilled', value: res };},(error) => {res[index] = { status: 'rejected', value: error };}).finally(() => {if (!--count) {resolve(res);}});});});
};

六. Promise.any实现

Mypromise.any = function(promiseList = []) {return new HYPromise((resolve, reject) => {const errors = [];let rejectedCount = 0promiseList.forEach((promise, index) => {HYPromise.resolve(promise).then(value => {resolve(value)},reason => {errors[index] = reason;rejectedCount++;if (rejectedCount === promiseList.length) {reject(new AggregateError(errors, 'All promises were rejected'))}})})})
}

六. 如何实现 Promise.map,限制 Promise 并发数

pMap([1, 2, 3, 4, 5], (x) => Promise.resolve(x + 1));
pMap([Promise.resolve(1), Promise.resolve(2)], (x) => x + 1);
// 注意输出时间控制
pMap([1, 1, 1, 1, 1, 1, 1, 1], (x) => sleep(1000), { concurrency: 2 });
class Limit {constructor (n) {this.limit = nthis.count = 0this.queue = []}enqueue (fn) {// 关键代码: fn, resolve, reject 统一管理return new Promise((resolve, reject) => {this.queue.push({ fn, resolve, reject })})}dequeue () {if (this.count < this.limit && this.queue.length) {// 等到 Promise 计数器小于阈值时,则出队执行const { fn, resolve, reject } = this.queue.shift()this.run(fn).then(resolve).catch(reject)}}// async/await 简化错误处理async run (fn) {this.count++// 维护一个计数器const value = await fn()this.count--// 执行完,看看队列有东西没this.dequeue()console.log(value);return value}build (fn) {if (this.count < this.limit) {// 如果没有到达阈值,直接执行return this.run(fn)} else {// 如果超出阈值,则先扔到队列中,等待有空闲时执行return this.enqueue(fn)}}
}Promise.map = function (list, fn, { concurrency }) {const limit = new Limit(concurrency)return Promise.all(list.map(async (item) => {item = await itemreturn limit.build(() => fn(item))}))
}const array = [1, 2, 3, 4, 5];
const concurrencyLimit = 2;const mapper = async (item) => {// 模拟异步操作await new Promise((resolve) => setTimeout(resolve, 1000));return item * 2;
};Promise.map([Promise.resolve(1), Promise.resolve(2)], mapper, { concurrency: 2 }).then((results) => {console.log(results);}).catch((error) => {console.error(error);});

七. 实现函数 promisify,把回调函数改成 promise 形式

function promisify(fn) {return function (...args) {let hasCb = args.some((v) => typeof v === "function");if (hasCb) {fn(...args);} else {return new Promise((resolve, reject) => {fn(...args, cb);function cb(err, data) {if (err) {reject(err);} else {resolve(data);}}});}};
}var func1 = function (a, b, c, callback) {let rst = a + b + c;callback(null, rst);
};var func2 = promisify(func1);
func2(1, 2, 3).then((rst) => {console.log("rst", rst);
}); //输出6

八. 并发请求控制

class ConcurrencyLimiter {constructor(maxConcurrency) {this.maxConcurrency = maxConcurrency;this.activeRequests = 0;this.queue = [];}async enqueue(request) {await this.waitUntilAllowed();try {this.activeRequests++;const response = await fetch(request.url);console.log(`Request ${request.id} completed with response:`, response);} catch (error) {console.error(`Request ${request.id} failed with error:`, error);} finally {this.activeRequests--;this.processQueue();}}waitUntilAllowed() {return new Promise((resolve) => {if (this.activeRequests < this.maxConcurrency) {resolve();} else {this.queue.push(resolve);}});}processQueue() {if (this.queue.length > 0 && this.activeRequests < this.maxConcurrency) {const nextRequest = this.queue.shift();nextRequest();}}
}// 创建并发器实例,最大请求数量为 5
const limiter = new ConcurrencyLimiter(5);// 请求列表示例
const requests = [{ id: 1, url: 'https://api.example.com/data/1' },{ id: 2, url: 'https://api.example.com/data/2' },{ id: 3, url: 'https://api.example.com/data/3' },// 更多请求...
];// 启动所有请求
requests.forEach((request) => {limiter.enqueue(request);
});function fetch(url) {return new Promise((resolve, reject) => {resolve(url)})
}

相关文章:

面试手写第二期 Promsie相关

文章目录 一. 手写实现PromiseA规范二. Promise.all实现三. Promise.race实现四. Promise.allsettled实现六. Promise.any实现六. 如何实现 Promise.map&#xff0c;限制 Promise 并发数七. 实现函数 promisify&#xff0c;把回调函数改成 promise 形式八. 并发请求控制 一. 手…...

Windows冷知识:最小化远程桌面与ffmpeg

Windows冷知识&#xff1a;最小化远程桌面与ffmpeg – WhiteNights Site 标签&#xff1a;ffmpeg, Windows, 冷知识 最小化远程桌面会中断ffmpeg的录制 我觉得这个应该算冷知识吧。 前情提要 远程桌面连接至虚拟机&#xff0c;并通过ffmpeg录屏 这里可能不太好理解。 我在用…...

12nm工艺,2.5GHz频率,低功耗Cortex-A72处理器培训

“ 12nm工艺&#xff0c;2.5GHz频率&#xff0c;低功耗Cortex-A72处理器培训” 本项目是真实项目实战培训&#xff0c;低功耗UPF设计&#xff0c;后端参数如下&#xff1a; 工艺&#xff1a;12nm 频率&#xff1a;2.5GHz 资源&#xff1a;2000_0000 instances 为了满足更多…...

网络编程套接字(2)

UDP数据报套接字编程 API介绍 DatagramSocket DatagramSocket是UDP的Socket,用于发送和接收数据报. 操作系统中有一类文件,就叫做socket文件(普通文件/目录文件:在硬盘上的) socket文件:抽象的表示了网卡这样的硬件设备 DatagramSocket就是对socket文件进行读写,也就是借助网…...

Elasticsearch:入门(二)

九. Elasticsearch的映射和分析 Elasticsearch的强大搜索引擎功能不仅源于其高效的分布式架构&#xff0c;还在于对数据的映射和分析的深度支持。通过合理的字段类型定义和灵活的分析器配置&#xff0c;可以使搜索更加精准、快速&#xff0c;并满足不同业务场景的需求。 9.1 …...

Debezium日常分享系列之:Debezium 2.6.0.Alpha1发布

Debezium日常分享系列之&#xff1a;Debezium 2.6.0.Alpha1发布 一、重大改变1.MongoDB2.重新选择列后处理器 二、改进和变化1.添加了新的匹配集合 API2.CloudEvents 架构名称自定义3.Oracle Infinispan 缓存改进4.支持 Spanner NEW_ROW_AND_OLD_VALUES 值捕获类型 一、重大改变…...

Phoncent博客,探索Rie Kudan的GPT创作之举

近日&#xff0c;大家都在谈论日本作家Rie Kudan&#xff0c;她凭借其小说《东京共鸣塔》&#xff08;"Tokyo-to Dojo-to"&#xff09;荣获了日本极具声望的芥川奖。这本小说引起了广泛的讨论和思考&#xff0c;因为令人惊讶的是&#xff0c;Kudan在其中直接引用了人…...

力扣hot100 划分字母区间 贪心 思维 满注释版

Problem: 763. 划分字母区间 文章目录 思路复杂度Code 思路 &#x1f468;‍&#x1f3eb; 代码随想录 复杂度 时间复杂度: O ( n ) O(n) O(n) 空间复杂度: O ( n ) O(n) O(n) Code class Solution {public List<Integer> partitionLabels(String s){// 创建哈希…...

linux下使用swap分区扩展内存

swap分区是什么&#xff1f; Swap分区是硬盘上的一个特殊区域&#xff0c;被操作系统用作虚拟内存。当系统的物理内存&#xff08;RAM&#xff09;被全部使用时&#xff0c;操作系统会将一部分数据移动到swap分区&#xff0c;以释放RAM上的空间。这个过程被称为"交换&quo…...

实现sleep函数

作用&#xff1a;让线程休眠&#xff0c;等到指定时间在重新唤起。 基于Date实现&#xff1a; 以上的代码不会让线程休眠&#xff0c;而是通过高负荷计算使cpu无暇处理其他任务。缺点是在sleep的过程中其他所有的任务都会被暂停&#xff0c;包括dom的渲染。sleep的过程中程序会…...

汽车销量可视化分析

目录 一.分析的背景、目的、意义 1、背景 2、目的 3、意义 二.数据来源 三.图表分析 1、汽车品牌销量柱状图 2、中国汽车销量柱状图 3、汽车销量前10排行柱状图 4、汽车厂商销量折线图 ​编辑5、汽车销量词云图 6、汽车车型销量 7、汽车价格分布雷达图 8、汽车分…...

代码随想录算法训练营DAY8 | 字符串(1)

一、LeetCode 344 反转字符串 题目链接&#xff1a; 344.反转字符串https://leetcode.cn/problems/reverse-string/ 思路&#xff1a;双指针法交换。 class Solution {public void reverseString(char[] s) {int n s.length;int left 0, right n-1;while(left < right){c…...

如何更改Outlook阅读邮件时的默认字体?

如果收到的邮件中未指定字体&#xff0c;outlook默认使用宋体显示。 如果觉得不好看&#xff0c;可以进行更改。但不是在outlook中更改&#xff0c;outlook中只是修改编辑器中的字体&#xff0c;和纯文本邮件浏览的字体&#xff0c;不能更改未指定字体的HTML邮件的显示字体。 …...

【C++基础入门】三、运算符(算术运算符、赋值运算符、比较运算符、逻辑运算符)

三、运算符 作用&#xff1a;用于执行代码的运算 本章我们主要讲解以下几类运算符&#xff1a; 运算符类型作用算术运算符用于处理四则运算赋值运算符用于将表达式的值赋给变量比较运算符用于表达式的比较&#xff0c;并返回一个真值或假值逻辑运算符用于根据表达式的值返回…...

ES7.17由于IP变化导致的故障及恢复

背景 1. k8s 升级&#xff0c;导致环境中的ES集群&#xff08;7.17版本&#xff09;重启 2. 集群由于在公有云环境&#xff0c;IP不固定&#xff08;重启后IP可能发生变化&#xff09;&#xff0c;通过 svc 进行访问 curl xxx-master-svc:9200/_cat/health 3. 由多个sts一…...

uniapp H5 touchstart touchend 切换背景会失效,或者没用

uniapp H5 touchstart touchend 切换背景会失效&#xff0c;或者没用 直接上代码 &#xff08;使用 class 以及 hover-class来设置样式&#xff09; class 设置默认的背景图或者样式 hover-class 来设置按下的背景图 或者样式 抬起 按下 <view class"mp_zoom_siz…...

【word visio绘图】关闭visio两线交叉的跳线(跨线)

【visio绘图】关闭visio两线交叉的跳线&#xff08;跨线&#xff09; 1 如何在Visio绘图中关闭visio两线交叉的跳线&#xff08;跨线&#xff09;第一步&#xff1a;打开Visio并创建您的图形第二步&#xff1a;绘制您的连接线第三步&#xff1a;关闭跳线第四步&#xff1a;手动…...

meson、ninja编译dpdk

解压目录meson编译dpdk meson buildmeson编译dpdk debug版 meson setup --buildtypedebug debugbuildmeson编译使用静态库&#xff0c;编译example meson .. --prefix/usr/local --buildtypedebugoptimized --default-librarystatic -Dexamplesallninja编译 ninjaninja安装…...

diff命令详解

diff是Unix系统的一个很重要的工具程序。 它用来比较两个文本文件的差异&#xff0c;是代码版本管理的基石之一。你在命令行下&#xff0c;输入&#xff1a; $ diff < 变动前的文件 > < 变动后的文件 >; diff就会告诉你&#xff0c;这两个文件有何差异。它的显示结…...

Backtrader 文档学习- Broker - Slippage

Backtrader 文档学习- Broker - Slippage 1.概述 回测无法保证真实的市场条件。无论市场模拟有多好&#xff0c;在真实市场条件下都可能发生滑点。这意味着&#xff1a; 请求的价格可能无法与真实市场的价格匹配 集成的回测broker支持滑点。以下参数可以传递给broker &#…...

CentOS7最小化安装后,这3个必做的配置(换源、设静态IP、更新)一个都不能少

CentOS7最小化安装后的三大关键配置实战指南刚完成CentOS 7最小化安装的系统就像毛坯房——虽然基础框架已经就位&#xff0c;但距离真正"拎包入住"还有一段距离。作为运维人员&#xff0c;我们最迫切的需求是快速搭建一个稳定、高效的基础服务器环境。本文将聚焦三个…...

Unity安装包瘦身实战:从2.3GB到680MB的工程化治理

1. 为什么一个500MB的Unity项目打包后会变成3GB&#xff1f;——安装包膨胀的真实逻辑“Unity安装包减肥”这六个字&#xff0c;听起来像在给软件做瑜伽&#xff0c;但实际是每个上线前夜都在咬牙硬扛的生存战。我做过7个已上线的Unity手游项目&#xff0c;最深的体会是&#x…...

Hermes Agent 总记不住你说的话?3 步治好 AI 助手的“健忘症“

你有没有这样的经历&#xff1a;你跟它说"每次写营销文章&#xff0c;记得先加载技能审核"&#xff0c;它答应得好好的。结果下一篇写出来&#xff0c;你又得说一遍同样的话。它就像一个只点头不记事的实习生——每轮对话都重头来过。又或者&#xff0c;昨天刚刚聊完…...

阿里巴巴运营/2026年阿里巴巴1688店铺效果越来越差的3个核心原因(附解决方案)

阿里巴巴运营/2026年阿里巴巴1688店铺效果越来越差的3个核心原因&#xff08;附解决方案&#xff09;最近很多工厂老板跟我说&#xff0c;小峰老师&#xff0c;我这1688店铺怎么越做越没效果了&#xff1f;明明以前还能来几个询盘&#xff0c;现在越来越少&#xff0c;是不是16…...

为什么92%的Midjourney水效渲染失败?——解析v6.1+版本流体折射权重、noise scale与--s值的黄金三角关系

更多请点击&#xff1a; https://codechina.net 第一章&#xff1a;为什么92%的Midjourney水效渲染失败&#xff1f;——问题现象与根本归因 大量用户在使用 Midjourney v6 生成「水效渲染」&#xff08;Water Efficiency Rendering&#xff09;类提示词时遭遇高频失败——表现…...

关于自指系统与算术障碍的跨领域猜想:一项探索性研究(世毫九实验室学术完善报告)

关于自指系统与算术障碍的跨领域猜想&#xff1a;一项探索性研究&#xff08;世毫九实验室学术完善报告&#xff09; 作者&#xff1a;方见华 单位&#xff1a;世毫九实验室 核心摘要 本报告针对世毫九实验室原创的探索性跨领域论文《关于自指系统与算术障碍的跨领域猜想&#…...

RK3588开发环境搭建三步曲:从零构建嵌入式Linux编译与烧录系统

1. 项目概述与核心价值拿到一块全新的RK3588核心板或开发板&#xff0c;看着它强大的八核CPU和NPU&#xff0c;心里盘算着各种AI和多媒体应用的你&#xff0c;是不是也曾在环境搭建这一步卡住过&#xff1f;从官方SDK下载、编译工具链配置&#xff0c;到内核编译、文件系统烧录…...

3分钟快速指南:如何使用Forza Painter将任何图片变成《极限竞速》专业涂装

3分钟快速指南&#xff1a;如何使用Forza Painter将任何图片变成《极限竞速》专业涂装 【免费下载链接】forza-painter Import images into Forza 项目地址: https://gitcode.com/gh_mirrors/fo/forza-painter 还在为《极限竞速&#xff1a;地平线》系列游戏中复杂的车辆…...

终极音乐整合方案:用MusicFree插件打造你的专属音乐中心

终极音乐整合方案&#xff1a;用MusicFree插件打造你的专属音乐中心 【免费下载链接】MusicFreePlugins MusicFree播放插件 项目地址: https://gitcode.com/gh_mirrors/mu/MusicFreePlugins 还在为音乐平台会员费烦恼吗&#xff1f;还在忍受不同平台间的歌曲版权割裂吗&…...

Windows安卓子系统WSA:三个实用技巧让你在Windows上流畅运行手机应用

Windows安卓子系统WSA&#xff1a;三个实用技巧让你在Windows上流畅运行手机应用 【免费下载链接】WSA Developer-related issues and feature requests for Windows Subsystem for Android 项目地址: https://gitcode.com/gh_mirrors/ws/WSA 你是否曾经梦想过在Windows…...