手写 Promise 静态方法:从原理到实现

手写Promise 理解promise底层原理 本文参考了此博客,在网上浏览了很多关于Promise的相关资料,promise可以说是JavaScript的重难点了,其中,很是感谢阮一峰老师的博客讲解以及MDN上的文档教程 如对Promise不太熟悉的同学,可以先浏览Promise工作原理分析,如有不同意见,欢迎讨论,一起进步。 Promise基本流程 function doSomething(){ var p1 = new Promise(function (resolve, reject) { setTimeout(()=. 阅读详情

在前端异步编程中,Promise 的静态方法扮演着至关重要的角色。它们为我们处理多个异步操作提供了简洁而强大的工具,让复杂的异步流程变得清晰可控。本文将深入剖析 Promise 常用静态方法的实现原理,带你一步步手写这些方法,彻底掌握它们的工作机制。

认识 Promise 静态方法

Promise 对象提供了多个静态方法,这些方法都是直接通过Promise构造函数调用的,无需实例化。它们的主要作用是对多个 Promise 实例进行组合操作,简化异步流程控制。

最常用的 Promise 静态方法包括:

  • Promise.all():等待所有 Promise 完成并收集结果
  • Promise.allSettled():等待所有 Promise 完成,无论成功失败
  • Promise.race():返回第一个完成的 Promise 结果
  • Promise.any():返回第一个成功的 Promise 结果

这些方法在实际开发中应用广泛,比如并发请求数据、设置请求超时、处理多个异步操作的结果等场景都离不开它们。

手写 Promise.resolve () 与 Promise.reject ()

作为最基础的 Promise 静态方法,resolve和reject用于快速创建处于特定状态的 Promise 实例。

Promise.resolve () 实现

Promise.resolve()的作用是返回一个处于 "已完成"(fulfilled) 状态的 Promise 实例,它接收一个参数作为完成值。如果参数本身就是一个 Promise 实例,则直接返回该实例。

Promise.myResolve = function(value) {
  // 如果参数是Promise实例,直接返回
  if (value instanceof Promise) {
    return value;
  }
  
  // 否则返回一个新的已完成Promise
  return new Promise((resolve) => {
    resolve(value);
  });
};

这个实现非常直接:首先检查传入的值是否已经是 Promise 实例,如果是则直接返回;否则创建一个新的 Promise 并立即用该值完成它。

Promise.reject () 实现

Promise.reject()与resolve类似,但它返回的是一个处于 "已拒绝"(rejected) 状态的 Promise 实例。

Promise.myReject = function(reason) {
  return new Promise((resolve, reject) => {
    reject(reason);
  });
};

注意reject方法不会像resolve那样检查参数是否为 Promise 实例,无论传入什么值都会作为拒绝原因。

手写 Promise.all ()

Promise.all()是最常用的 Promise 组合方法之一,它接收一个 Promise 数组 (或可迭代对象),返回一个新的 Promise。当所有输入的 Promise 都完成时,新 Promise 才会完成,结果是一个包含所有完成值的数组;如果有任何一个输入的 Promise 被拒绝,新 Promise 会立即被拒绝。

实现思路

  1. 接收一个可迭代对象作为参数,通常是数组
  1. 返回一个新的 Promise 实例
  1. 遍历输入的所有 Promise
  1. 维护一个计数器和结果数组,记录已完成的 Promise 数量和结果
  1. 当所有 Promise 都完成时,用结果数组完成新 Promise
  1. 如果有任何一个 Promise 被拒绝,立即用该原因拒绝新 Promise

代码实现

Promise.myAll = function (promises) {
    // 返回一个新的Promise实例
    return new Promise((resolve, reject) => {
        // 存储所有成功的结果,按传入数组的顺序排列
        let results = [];
        // 记录传入的Promise总数量(用于判断是否所有Promise都已处理)
        let count = 0;
        // 记录已成功完成的Promise数量
        let fulfilledCount = 0;
        for (const p of promises) {
            let i = count++;

            // 将当前值包装为Promise(处理非Promise值的情况,如普通数字、字符串等)
            Promise.resolve(p)
                .then((data) => {
                    results[i] = data;
                    fulfilledCount++;

                    // 当所有Promise都成功时(已成功数量 === 总数量)
                    if (fulfilledCount === count) {
                        // 用结果数组resolve外部Promise
                        resolve(results);
                    }
                }, 
                // 当当前Promise失败时的回调:直接调用外部Promise的reject
                // 符合Promise.all"一错即错"的特性,立即返回第一个失败原因
                reject);
        }

        // 特殊情况:如果传入的是空数组,直接resolve空数组
        // 此时循环未执行,count保持0,直接返回空结果
        if (count === 0) {
            resolve(results);
        }
    });
};

关键细节

  • 保持结果数组的顺序与输入数组一致,即使某些 Promise 先完成
  • 只要有一个 Promise 被拒绝,就会立即触发拒绝,且只触发一次
  • 输入数组中的非 Promise 值会被Promise.resolve自动转换

手写 Promise.race ()

Promise.race()的行为类似于 "赛跑",它接收一个 Promise 数组,返回一个新的 Promise。这个新 Promise 会跟随第一个完成 (无论是完成还是拒绝) 的 Promise,采用它的结果或原因。

实现思路

  1. 接收一个可迭代对象作为参数
  1. 返回一个新的 Promise 实例
  1. 遍历输入的所有 Promise
  1. 一旦有任何一个 Promise 完成或拒绝,就用它的结果或原因处理新 Promise

代码实现

Promise.myRace = function (promises) {
    return new Promise((resolve, reject) => {
        for (const p of promises) {
            Promise.resolve(p).then(resolve, reject);
        }
    })
}

典型应用:请求超时处理

race方法非常适合实现请求超时功能:

// 模拟一个异步请求
function fetchData() {
  return new Promise((resolve) => {
    setTimeout(() => resolve('数据加载成功'), 3000);
  });
}
// 超时控制器
function timeout(ms) {
  return new Promise((_, reject) => {
    setTimeout(() => reject(new Error('请求超时')), ms);
  });
}
// 使用race实现超时控制
Promise.myRace([fetchData(), timeout(2000)])
  .then(console.log)
  .catch(console.error); // 会输出"请求超时"

手写 Promise.allSettled ()

Promise.allSettled()等待所有输入的 Promise 都 "落定"(settled),即无论是完成还是拒绝,都会等待所有 Promise 处理完毕。它返回的 Promise 会完成一个数组,每个元素表示对应 Promise 的结果,包含状态和值 / 原因。

实现思路

  1. 接收一个可迭代对象作为参数
  1. 返回一个新的 Promise 实例
  1. 遍历输入的所有 Promise
  1. 每个 Promise 完成或拒绝后,都记录其状态和结果
  1. 当所有 Promise 都落定后,用结果数组完成新 Promise

代码实现

Promise.myAllSettled = function(promises){
    let results = [];
    for (const p of promises) {
        results.push(Promise.resolve(p).then((data) => ({
            status:"fulfilled",
            data
        }),
    (reason) => ({
        status:"rejected",
        reason
    })
))
    }
    return Promise.all(results);
}

应用场景

allSettled特别适合需要知道所有异步操作结果的场景,比如批量处理数据时,即使某些操作失败,也需要知道成功的部分并继续处理。

手写 Promise.any ()

Promise.any()与all相反,它等待第一个 "成功完成" 的 Promise。只要有一个输入的 Promise 成功完成,它就会用该结果完成;如果所有输入的 Promise 都被拒绝,它会用一个包含所有拒绝原因的AggregateError拒绝。

实现思路

  1. 接收一个可迭代对象作为参数
  1. 返回一个新的 Promise 实例
  1. 遍历输入的所有 Promise
  1. 只要有一个 Promise 成功完成,就用该结果完成新 Promise
  1. 如果所有 Promise 都被拒绝,收集所有原因并拒绝新 Promise

代码实现

Promise.myAny = function(promises) {
  return new Promise((resolve, reject) => {
    if (!Array.isArray(promises)) {
      return reject(new TypeError('Argument must be an array'));
    }
    
    const errors = []; // 收集所有拒绝原因
    let rejectedCount = 0;
    
    if (promises.length === 0) {
      return reject(new AggregateError([], 'All promises were rejected'));
    }
    
    promises.forEach((promise) => {
      Promise.myResolve(promise).then(
        (value) => {
          // 第一个成功的Promise会触发resolve
          resolve(value);
        },
        (reason) => {
          errors.push(reason);
          rejectedCount++;
          
          // 所有Promise都被拒绝时
          if (rejectedCount === promises.length) {
            reject(new AggregateError(errors, 'All promises were rejected'));
          }
        }
      );
    });
  });
};

与 race 的区别

any和race都关注 "第一个有结果的 Promise",但有重要区别:

  • race返回第一个 "落定" 的 Promise,无论成功还是失败
  • any返回第一个 "成功完成" 的 Promise,忽略拒绝的 Promise,直到所有都拒绝才会拒绝

测试与验证

实现完成后,我们需要验证这些静态方法是否符合预期行为。以myAll为例:

// 测试Promise.myAll
const p1 = Promise.resolve(1);
const p2 = new Promise(resolve => setTimeout(() => resolve(2), 100));
const p3 = 3;
Promise.myAll([p1, p2, p3]).then(result => {
  console.log(result); // [1, 2, 3]
});
// 测试拒绝情况
const p4 = Promise.reject('出错了');
Promise.myAll([p1, p4, p2]).catch(reason => {
  console.log(reason); // '出错了'
});

同样的方式可以测试其他方法,确保它们的行为与原生 Promise 静态方法一致。

总结

通过手写这些 Promise 静态方法,我们深入理解了它们的内部工作机制:

  • all等待所有完成,或第一个拒绝
  • allSettled等待所有落定,收集所有结果
  • race返回第一个落定的结果
  • any等待第一个成功,或所有拒绝

掌握这些方法的实现原理,不仅能帮助我们更好地在项目中应用它们,还能提升我们对异步编程的理解。在实际开发中,选择合适的 Promise 静态方法可以大大简化异步流程控制,写出更清晰、更健壮的代码。

python -- 海洋气象科研论文中常用绘图配色汇总 当我学到一定基础,有自己的理解能力的时候,会去阅读一些前辈整理的书籍或者手写的笔记资料,这些笔记详细记载了他们对一些技术点的理解,这些理解是比较独到,可以学到不一样的思路。Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照下面的知识点去找对应的学习资源,保证自己学得较为全面。观看全面零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。可以通过自定义选取不同颜色的rgb,通过自定义的方式构建colormap。 阅读详情

相关推荐

【算法】基于STM32的MPU6050卡尔曼滤波算法(入门级)

1. 简介 卡尔曼滤波(Kalman filtering)是一种利用线性系统状态方程,通过系统输入输出观测数据,对系统状态进行最优估计的算法。由于观测数据中包括系统中的噪声和干扰的影响,所以最优估计也可看作是滤波过程。详情见:卡尔曼滤波简介 MPU6050的解算主要有三种姿态融合算法:四元数法 、一阶互补算法和卡尔曼滤波算法。我们常用的DMP库使用的是四元数法,本文采用卡尔曼滤波算法,使用RT-Thread国产操作系统,利用env工具进行串口、模拟IIC环境配置,使用10ms的线程进行卡尔曼滤波解算。 2.

weixin_44549777的博客 3万+

手写一个promise用法_图解 Promise 实现原理(四):Promise 静态方法实现

作者:Morrain转发链接:https://mp.weixin.qq.com/s/Lp_5BXdpm7G29Z7zT_S-bQ前言Promise 是异步编程的一种解决方案,它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。更多关于 Promise 的介绍请参考阮一峰老师的 ES6入门 之 Promise 对象。很多同学在学习 Promise 时,知其然...

weixin_36184940的博客 802

测试用例经典练习之微信发红包测试用例

微信发红包测试用例

ZCYaiCLX3344的博客 1万+

手写Promise的静态方法

最近对promise原理的理解,手写下其中的静态方法。

weixin_45403802的博客 889

手把手教你学Simulink——基于Simulink的轮毂电机独立驱动转矩矢量分配

阐述了轮毂电机独立驱动的核心价值与转矩分配的必要性在 Simulink 中实现了完整的“上层稳定控制 + 下层最优分配”架构对比了三种分配策略在极限工况下的性能差异提供了工程落地的关键考量特斯拉 Cybertruck(后轮双电机矢量控制)Rivian R1T(四电机坦克掉头)宝马 iX(精准牵引力控制)核心思想“以软件定义底盘,以算法驾驭动力;化四轮之独立,为整车之协同。—— 让汽车在极限边缘依然从容不迫。

MHD0815的博客 372

openGauss学习笔记-280 openGauss性能调优-实际调优案例09-修改启动参数解决TPCC大幅度波动

openGauss学习笔记-280 openGauss性能调优-实际调优案例09-修改启动参数解决TPCC大幅度波动280.1 现象描述280.2 优化分析 openGauss学习笔记-280 ope

超哥的博客 309

promise原理及手写实现

实现一个基本的Promise类,首先需要定义类并添加executor回调方法,接收resolve和reject作为参数。接着定义Promise的三种状态,并实现then方法。对于异步操作,需要在pending状态下将回调函数存入数组,待状态改变后依次执行。链式调用的实现需要在then方法中返回一个新的Promise对象,以便继续调用then方法。通过这些步骤,可以逐步实现一个功能完整的Promise类。

weixin_52797317的博客 507

PCB仿真软件:Altium Designer_(6).PCB布线设计:自动布线与手工布线

通过以上步骤,我们完成了一个简单的PCB设计案例。在这个过程中,我们使用了自动布线和手工布线的综合策略,确保布线质量符合设计要求。创建PCB项目:在Altium Designer中创建一个新的PCB项目。导入原理图:将原理图文件导入到PCB项目中。设置布线规则:通过设置必要的布线规则,如线宽、间距等。启动自动布线:使用自动布线器进行初步布线。手工优化布线:通过手工布线工具优化关键信号的布线路径。保存和导出PCB文件:保存PCB文件并导出Gerber文件,用于生产。

kkchenjj的博客 2523

【JavaScript】必须要会的手写Promise

写在前面Promise是ES6中核心的语法,也是面试最常问的一部分,所以搞懂它的执行规则是必须,学会手写会让你在面试中脱颖而出,迈出拿到offer坚实的一步~在之前的文章中,我翻译了Pr...

Alberqing_的博客 413

剪映专业版教程:用AI生成音乐MV并重新制作画面—《漂泊与归梦》完全原创实战

本文详细拆解如何用AI生成音乐MV并重新制作画面的全流程。以歌曲《漂泊与归梦》为例,首先用AI将歌词转化为带音乐的MP4文件;导入剪映后分离音频并删除原视频,通过“识别字幕”功能提取歌词文本并逐句核对修正;接着设置“向右擦除”动画并锁定字幕轨道;最后根据歌词意境配置动漫、风景等非真人画面规避审核风险。教程涵盖从AI生成、音频分离、字幕提取到画面重制的每个环节,助你打造完全原创、无侵权风险的音乐短视频。

深耕计算机专业知识与技术。 1077

视觉Transformer实战 | 将卷积引入视觉Transformer(CvT)

CvT 是一种融合卷积神经网络与 Vision Transformer 优势的视觉模型,旨在解决 ViT 缺乏平移不变性和局部性等归纳偏置的问题。CvT 采用分层结构逐级降采样,使用卷积词元嵌入代替传统 patch 切分,引入卷积投影替代线性投影。这些设计使得 CvT 能够去除位置编码,在高分辨率输入下表现更优。本节深入解析 CvT 的核心原理,并提供完整的 PyTorch 代码实现,演示如何在实际数据集上训练和评估 CvT 模型。

盼小辉丶的博客 727

手写Promise - 常用静态方法all、resolve、reject、race

手写Promise - 实现一个基础的Promise 手写Promise - 实例方法catch、finally 手写Promise - 常用静态方法all、resolve、reject、race 先来回顾一下,上一章节之后的代码。 class WPromise { static pending = 'pending'; static fulfilled = 'fulfilled'; static rejected = 'rejected'; constructor(executor) { t

willemwei023的博客 679

【DRAM存储器四十六】LPDDR5介绍--基本操作之行操作、读、写

简述LPDDR5的行操作和读写时序

highman110的博客 764

Promise手写实现

回忆一下Promise的基本知识点,通常有三个状态:pending、fulfilled、rejected。它有一个then方法,用于处理异步操作的结果,还有catch方法用于处理错误。另外,Promise还有resolve和reject方法,以及静态方法如all、race、resolve、reject等。

君子-如兰的博客 1076

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

2022年了--你还不会手写promise? 完成promise的所有实现

手写promise,将静态方法和实例方法都进行了一遍实现。也可以实现链式调用。 /* * @Author: 毛毛 * @Date: 2022-01-03 10:17:47 * @Last Modified by: 毛毛 * @Last Modified time: 2022-01-03 10:17:47 */ /** * * 手写promise * @class MaoPromise */ class MaoPromise { /** * 正在执行的状态 *

听雨少年的博客 3129

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

手写Promise原理实现

手写Promise源码 从构造函数开始 Promise就是一个类,在执行这个类的时候需要传递一个执行器进去,执行器会立即执行。 Promise中有三种状态 分别为:成功fulfilled失败rejected等待pending,一旦状态确定就不可更改。 //Promise 类核心逻辑实现 const PENDING = 'pending';//等待 const FULFILLED = 'filfulled';//成功 const REJECTED = 'rejected';//失败 class

yu923023913的博客 245

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

手写简版promise(三)实现周边方法

周边方法 promise.resolve() promise.reject() promise.all() promise.race() 1、实现MyPromise.resolve() MyPromise.resolve这个可以使用MyPromise类调用,但却不能使用实例之后的对象调用说明这个方法是自身的属性,是静态方法我们前面需要加static 描述,这个方法很简单,就是我们在实例化MyPromise这个类时候需要resolve就可以。reject类似 static resolve(val) {

qq_39183005的博客 168

Promise原理 及其手写实现

通过new关键字调用构造函数Promise(),需要一个函数作为参数,可以是箭头函数 或者 匿名函数- 函数内需要传递两个参数:resolve、reject,都是函数名,可以向promise实例中- 通过Promise实例方法then(),then需要回调函数作为参数(实际需要两个)- 通过resolve存储的数据,会调用then第一个参数(函数)返回- promise中then、catch、finally都会返回一个新的promsie,新的promise中存储的是then()中回调函数的返回值。

weixin_69603897的博客 219

实现Promise的原型方法--前端面试能力提升

有如下: 原型方法:then、catch、finally静态方法:resolve、reject、race、all、allSettled、any Promise.resolve(value) 将给定的一个值转为Promise对象。 参考:前端手写面试题详细解答const p=Promise.reject(‘error’) 相当于下方函数: const p=new Promise(reject=>{ reject(‘11111’) })Promise.reject()方法返回一个带有拒绝原因的Promise对

helloworld1024fd的博客 348

面试手写实现Promise.all

曾经真实发生在一个朋友身上的真实事件,面试官让他手写一个Promise.all,朋友现场发挥不太好,没有写出来,事后他追问面试官给的模糊评价是基础不够扎实,原理性知识掌握较少... 当然整场面试失利,并不仅仅是这一个题目,肯定还有其他方面的原因。但是却给我们敲响一个警钟:Promise手写实现、Promise静态方法实现早已经是面试中的高频考题,如果你对其还不甚了解,耽误你10分钟,我们一起干到他懂O(∩_∩)O。

百创科技 1142

手写promise

手写promise 需要参考 promiseA+规范 promises 测试组件 npm install promises-aplus-test -g promises-aplus-test promise.js // promise就是一个类 // 1.promise 有三个状态: 成功态(resolve) 失败态(reject) 等待态(pending) (又不成功又不失败) // 2.用户自己决定失败的原因和成功的原因 成功和失败也是用户定义的 // 3.promise 默认执行器时立即执行 //

weixin_43801428的博客 351

从零开始手写一个Promise,彻底理解异步编程的核心原理

Promise使得处理异步代码变得更加直观和易于管理,尤其是在需要组合多个异步操作或者处理异常的时候。Promise 提供了一种比传统的回调函数更好的解决方案来处理异步编程中的复杂性

mutuyxy的博客 383

《JavaScript》异步编程(三)深入浅出Promise,附大厂真题面经

今天的文章可谓是积蓄了我这几年来的应聘和面试经历总结出来的经验,干货满满呀!如果你能够一直坚持看到这儿,那么首先我还是十分佩服你的毅力的。所以看完之后,还是多多行动起来吧!可以非常负责地说,如果你能够坚持把我上面列举的内容都一个不拉地看完并且全部消化为自己的知识的话,那么你就至少已经达到了中级开发工程师以上的水平,进入大厂技术这块是基本没有什么问题的了。// 使用setTimeout模拟异步try {// 值传进去,并且实现reslove(value)}, 0)// 状态等于reject。

2401_84094868的博客 1139

《JavaScript》异步编程(三)深入浅出Promise

技术是没有终点的,也是学不完的,最重要的是活着、不秃。零基础入门的时候看书还是看视频,我觉得成年人,何必做选择题呢,两个都要。喜欢看书就看书,喜欢看视频就看视频。最重要的是在自学的过程中,一定不要眼高手低,要实战,把学到的技术投入到项目当中,解决问题,之后进一步锤炼自己的技术。技术学到手后,就要开始准备面试了,找工作的时候一定要好好准备简历,毕竟简历是找工作的敲门砖,还有就是要多做面试题,复习巩固。有需要面试题资料的朋友点击这里可以免费领取。并且实现reslove(value)}, 0)

2401_84093973的博客 346

Promise以及手动实现

Promise原理及实现

weixin_42683639的博客 475

本地化部署 DeepSeek,构建单细胞与空间转录组 AI 分析平台

本地化部署 DeepSeek,构建单细胞与空间转录组 AI 分析平台

weixin_53637133的博客 178
上一篇: 实现大文件上传全流程详解(补偿版本)
下一篇: 前端必会:Promise 全解析,从原理到实战
程序员职业指南
博客等级 码龄4年 2138粉丝 960原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值