深度解析Promise.all的核心功能并手写实现

2023-11-02

在之前的文章中,已经手写实现了Promise的核心功能,包括resolverejectthenPromise还有一些拓展方法,比如Promise.all

在手写实现一些原生提供的方法时,第一步要做的事情就是先了解这个方法的使用过程和基本原理。

所以我们先了解一下Promise.all做的事情。

原生Promise.all的使用

以下是MDN文档的简述:

Promise.all() 方法接收一个promiseiterable类型(注:ArrayMapSet都属于ES6iterable类型)的输入,并且只返回一个Promise实例, 那个输入的所有promiseresolve回调的结果是一个数组。这个Promiseresolve回调执行是在所有输入的promiseresolve回调都结束,或者输入的iterable里没有promise了的时候。它的reject回调执行是,只要任何一个输入的promisereject回调执行或者输入不合法的promise就会立即抛出错误,并且reject的是第一个抛出的错误信息。

简单来说就是批量化处理promise实例以一个数组或者类数组的方式存储,当所有的promiseresolve都执行完成,或者存在任意一个promisereject被执行,都立即返回。

要么全成功,一起返回,只要有一个失败,就立即返回当前失败的内容。

下面我们简单用一下。

let promise1 = new Promise((resolve, reject) => {
  resolve(1);
})
let promise2 = new Promise((resolve, reject) => {
  resolve(2);
})
let promise3 = new Promise((resolve, reject) => {
  resolve(3);
})

Promise.all([promise1, promise2, promise3])
.then(res => {
  console.log(res);
}, err => {
  console.log(err);
})

在这里插入图片描述

输出的结果如上所示。

我们知道原生Promise.all的基本原理和使用方法之后,试着来自己实现以下。

手写实现Promise.all

Promise.all = function(promises) {
  let results = [];
  let length = promises.length;
  let promiseCount = 0;
  return new Promise((resolve, reject) => {
    for (let i of promise1) {
      Promise.resolve(i).then(res => {
        results.push(res);
        promiseCount ++;
        
        if (promiseCount === length) {
          resolve(results);
        }
      }, err => {
        reject(err);
      })
    }
  })
}

简单解释一下上面的代码,首先函数接收一个参数promises,代表保存了很多promise实例的数组或类数组。

results是用来存储每个promise实例执行之后的结果。因为最后要以数组的方式将所有promise的执行结果返回。

promiseCount是记录promise的执行次数,当所有的参数中所有的promise实例都执行完成,就将results返回。

接下来,return一个新的promise实例。在官方文档中有说明,Promise.all方法最终会返回一个Promise实例。

在构造函数中的处理,循环接收到的 promises参数,挨个执行,需要注意的一点是,避免使用者传入非Promise类型的元素,所以在遍历的时候将每个元素都用Promise.resolve包裹一下。

接下来的操作就是将当前遍历的promise实例的resolve执行结果添加到results数组中,promiseCount ++,代表当前实例执行完了。如果promiseCount === length就代表,所有promise元素都执行完了。返回存储所有promise执行结果的results数组即可。

如果有任意一个promise元素执行的是reject方法,立即结束当前循环,执行reject方法,返回报错信息。

其实以上源码可以实现基本功能,但是还有点瑕疵。在给往results数组中push当前遍历的promise执行结果时,其实不准确。因为promise实例中处理的可能是异步事件,大部分也都是异步事件。直接push并不准确。

比如传入的promiseresolve输出是[1, 2, 3]; 如果第一个promise实例中存在异步事件,比如加了一个定时器,按照当前的写法,直接 push的话Promise.all返回的一定是[2, 3, 1]; 这其实是不对的。应该按照顺序返回。

用原生的Promise.all试一下。

let promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(1);
  })
})
let promise2 = new Promise((resolve, reject) => {
  resolve(2);
})
let promise3 = new Promise((resolve, reject) => {
  resolve(3);
})

Promise.all([promise1, promise2, promise3])
.then(res => {
  console.log(res);
}, err => {
  console.log(err);
})

在这里插入图片描述
与猜测一致。无论返回的携带有promise执行结果的数组中的顺序应该与传入时的顺序一致。

优化版的源码如下:

Promise.all = function(promises) {
  let results = [];
  let length = promises.length;
  let promiseCount = 0;
  return new Promise((resolve, reject) => {
    for (let i = 0; i < promises.length; i++) {
      Promise.resolve(promises[i]).then(res => {
        results[i] = res;
        promiseCount ++;
        
        if (promiseCount === length) {
          resolve(results);
        }
      }, err => {
        reject(err);
      })
    }
  })
}

解决方案其实就是,通过当前遍历传入参数的索引来作为results的索引,往里面添加。

这样就一定是按输入的顺序返回。

欢迎大家关注我的公众号,有很多关于前端的内容哦
QQ:505417246
WX:18331092918
公众号:Code程序人生
B站账号:LuckyRay123
个人博客:http://rayblog.ltd/

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

深度解析Promise.all的核心功能并手写实现 的相关文章

  • Javascript 函数与 php 一样吗?

    我在网站上使用 WebIM 提供聊天支持 我希望能够在客户端启动聊天会话时设置一个计时器 如果操作员 技术人员在 x 秒内没有响应 我希望页面重定向到客户端可以留言的另一个页面 有点像 请稍等 我们尝试联系您 这样 如果所有技术人员都太忙或
  • 为什么 Eclipse 有时会对 JavaScript 中的数组数组发出警告?

    在 Eclipse 中 以下 JavaScript 行 var a1 1 2 3 4 生成警告 Type mismatch cannot convert from Number to any Type mismatch cannot con
  • 如何用js获取一个月的4个星期一?

    我正在构建一个图表 其中 x 轴应该是一个月的四个星期 我只想显示该月的四个星期一 我已经有了currentMonth和currentYear变量 而且我知道如何获取该月的第一天 我所需要的只是将一个月的四个星期一放入数组中 所有这些都在同
  • 当名称是数组时如何使用 Javascript 修改 HTML Select

    我有两个同名的 html select 对象 它们是具有不同索引的数组 我想做的是 如果从类别 0 选择元素中选择 关闭 我想禁用类别 1 元素 我一直在尝试使用 document getElementsByName 但无法弄清楚如何专门针
  • jQuery - 将所有展开的文本包装在 p 标签中

    我遇到以下情况 以下代码被写入我的页面 div Some text here which is not wrapped in tags p Some more text which is fine p p Blah blah another
  • 如何检测不渲染 .png 透明的浏览器

    我有这段代码可以根据一周中的某一天渲染图像 但在 IE6 及更低版本以及可能其他一些浏览器中 它不会呈现 png 不透明度 所以我想稍微改变一下 这样它就会检测到不渲染 alpha 透明度的浏览器 并告诉他们加载这个图像 img horar
  • javascript中文本区域限制每行的字符数

    我试图用 javascript 限制文本区域中每行的字符数 我在这里看到了一些例子 但并不完全符合我的要求 我写了一些东西 只有当你每次添加超过限制时才可以 换句话说 我每行有 10 个字符的限制 如果你总是输入至少 10 个字符就可以正常
  • 通过 AJAX 发送 XML

    我在 jQuery 中创建了一个 xml 文档 如下所示 var xmlDocument
  • 使用什么事件来在选择文本框中的值时显示警报消息

    我正在使用 jquery 的自动完成 api 来从数据库中获取名称 但是我想在从显示的文本框中选择名称时显示一条警报消息 我将显示一个图像以便更好地理解 当我输入 S 时 它将显示所有包含 S 的记录 所以问题是 如果我选择例如 Spars
  • Javascript:如何根据 html 标签扩展用户选择?

    乐代码 http jsfiddle net frf7w 12 http jsfiddle net frf7w 12 所以现在 当前的方法将完全按照 选择的方式获取所选文本 并添加标签 以便在显示时页面不会爆炸 但我想做的是 就是说 当用户选
  • Backbone.js 与 Google 地图 - 有关此问题和侦听器的问题

    我有一个为 Google Maps v3 创建的模块 我正在尝试将其转换为 Backbone js 视图构造函数 到目前为止 这是我的视图模块 我将解释代码后遇到的问题 pg views CreateMap Backbone View ex
  • 如何使用javascript隐藏div

    我想使用 Javascript 隐藏一个 div 下面是我的div div class ui dialog titlebar ui widget header ui corner all ui helper clearfix span cl
  • 设置股票数据 Highcharts xAxis 的格式

    我已经浏览了需要为 xAxis 属性设置的 Highcharts 选项来格式化时间标签 但没有运气了解这对于这种情况到底是如何工作的 我在白天 盘中 检索了股票的动态数据 我需要显示这些数据 因为检索的数据每天从 9 30 开始到 17 0
  • json、rails、javascript 中的解析错误

    我需要将 ruby 数组放入 javascript 数组中 但出现解析错误 var characters 这就是我将 ruby 嵌入到内联 javascript 中的方式 但它出现了解析错误 我应该如何将此 ruby 数组放入 javasc
  • 从 html 页面和 javascript 调用 java webservice

    我正在尝试从 javascript 调用 java 实现的 Web 服务 使用 NetBeans IDE 我读过很多关于 jQuery 和 AJAX 的内容 但我似乎无法掌握它 假设我的 Web 服务 WSDL 位于 http localh
  • 如何在 JavaScript 中从代理对构造 UTF-16 字符?

    以下计算 Unicode 代码点的 UTF 16 代理对 戴着医用口罩的脸 https emojipedia org face with medical mask 但是如何从代理对构造字符以在字符串中使用呢 const codepoint
  • 需要根据用户选择有条件地渲染具有 X 行数的部分

    我有一个反应组件 其中包含一个下拉列表 其中的选项包括none 1 5 and 13 根据用户选择的数字 我需要渲染一个部分 其中包括许多行 每个行都有字段名称和下拉列表 如果用户不选择任何一个 我需要整个附加配置部分消失 新部分中的每个下
  • Skrollr 添加空白

    我已经尝试了一切 我在谷歌上阅读了 4 5 页试图找到适合我的修复程序 已经筋疲力尽了 即使我使用 skrollr 示例 我的问题仍然存在 不是说他们做错了什么 我知道我只是没有正确理解它 因此 我上传了一个演示 仅在移动设备上展示这个尴尬
  • 如何使用 HTML5 Javascript Canvas 获取三个碰撞形状的交集并删除不碰撞的部分?

    我最近专门针对 KonvaJs 发布了类似的问题here https stackoverflow com questions 64603077 how can i get the intersection of three shapes c
  • 如何在 JSP 编辑器中激活 javascript 的语法着色 - Eclipse

    在某些情况下 javascript 确实必须位于 JSP 页面中 而不是位于单独的文件中 有些框架还使用Javascript做一些事情 以便用户将其包含到JSP标签中 这样JS就不会出现在

随机推荐