在理清Promise.all()中每个流程的时候实在是头大,理了半天,做此记录以便回顾

promise部分源码如下,只摘取用到的部分

function Promise(excutor) {const self = thisself.status = 'pending' //给promise对象添加status属性,初始值为pendingself.data = undefined //给promise对象指定data属性,用于储存结果数据self.callbacks = [] //每个元素的结构:{ onResolved() {} ,  onRejected() {} }function resolve(value) {//如果当前状态不是pending,直接结束if (self.status !== 'pending') {return}//将状态改为resolvedself.status = 'resolved'//保存value数据self.data = value//如果有待执行的callback函数,立即异步执行onResolvedif (self.callbacks.length > 0) {setTimeout(() => {//放入队列中执行所有成功的回调self.callbacks.forEach(callbacksObj => {callbacksObj.onResolved(value)});});}}function reject(reason) {//如果当前状态不是pending,直接结束if (self.status !== 'pending') {return}//将状态改为rejectedself.status = 'rejected'//保存value数据self.data = reason//如果有待执行的callback函数,立即异步执行onRejectedif (self.callbacks.length > 0) {setTimeout(() => {//放入队列中执行所有成功的回调self.callbacks.forEach(callbacksObj => {callbacksObj.onRejected(reason)});});}}//立即同步执行excutortry {excutor(resolve, reject)} catch (error) {//如果执行器抛出异常,则失败reject(error)}}Promise.prototype.then = function (onResolved, onRejected) {const self = thisreturn new Promise((resolve, reject) => {if (self.status === 'pending') {//假设当前状态时pending状态//此时的下一行的this,是调用then方法的promise,//因为这是处于新promise的excutor'中,this.callbacks.push({onResolved: function () {try {//判断返回的是什么//返回的是promiseconst result = onResolved(self.data)if (result instanceof Promise) {result.then(value => resolve(value),reason => reject(reason))} else {//返回的是值,多次循环最终都是值,再包装成promise向上传递//有点类似递归resolve(result)}} catch (error) {reject(error)}},onRejected: function () {try {//判断返回的是什么//返回的是promiseconst result = onRejected(self.data)if (result instanceof Promise) {result.then(value => resolve(value),reason => reject(reason))} else {//返回的是值,多次循环最终都是值,再包装成promise向上传递//有点类似递归resolve(result)}} catch (error) {reject(error)}}})}}/*Promise函数对象的race()方法 返回一个promise,其结果由第一个完成的promise的状态*/Promise.race = function (promises) {return new Promise((resolve, reject) => {for (let i = 0; i < promises.length; i++) {promises[i].then(v => {resolve(v)}, r => {reject(r)})}})}

用作测试例子代码如下,promise结果均异步输出,excutor用settimeout

        let p1 = new Promise((resolve, reject) => {setTimeout(() => {resolve('1')}, 1000);})let p2 = new Promise((resolve, reject) => {// resolve('2')setTimeout(() => {resolve('2')}, 1000);})let p3 = new Promise((resolve, reject) => {// resolve('3')setTimeout(() => {resolve('3')}, 1000);})p1.aaa='我是标志'let result1 = Promise.race([p1,p2, p3])console.log(result1);

具体流程文字如下:
1.
首先p1,p2,p3三个实例对象被创建,但是其中的excutor没有执行,暂时进入异步队列等待同步任务完成;
2.
进入Promise.race内部:
首先会创建一个新的Promise,为了方便叙述,
命名为newP,该对象即是测试html中的result,最后输出的内容

    Promise.race = function (promises) {return new Promise((resolve, reject) => {for (let i = 0; i < promises.length; i++) {promises[i].then(v => {resolve(v)}, r => {reject(r)})}})}

3.
进入构造newP对象的构造函数代码中,
此时newP的状态为pending,data为undefined
然后进入newP的excutor,即进入for循环

4.
会进入promises数组中第一个promise的then方法,循环后续都是一样的,只描述第一个循环的流程即可,

进入后会先构造一个新的Promise对象,记为insideP,进入构造函数内部的代码后,
insideP状态为pending,data为undefined

然后进入excutor,即下图里面,进行if判断
因为p1p2p3都处于pending,(此时的循环针对p1)所以会push一个对象{onResolved, onRejected}给p1的callbacks数组

5.
结束第一个循环,后续循环同理,直至同步代码全部完成,此时控制台打印了result但是newP的状态是pending,(后续会自动改变)
此时异步队列开始运行,p1p2p3依次运行,
此时各个对象状态如下,全是pending

6.
p1的excutor里面的resolve(1)开始运行
首先改变p1pending为resolved,data为1,
因为callbacks数组在第4步被push进了一个对象,所以length不为0,

此时由与settimeout,所以会将其放入异步队列,然后进入p2的resolve(2),同理p3的resolve(3)分别改变p2和p3的pending和data,但是不进入下一步操作,因为是异步的

同步都完了,进入异步操作,此时还处于p1的resolve里的if语句,会执行下面的异步操作
进入并执行回调函数onResolved()

7.
跳转到then方法里面的onResolved方法处,

然后再因为onResolved是then的参数,跳转到调用then方法时的参数处,即循环的地方

此时可以看见,调用的是resolve()方法,但要明确是谁在调用该方法,本文的上一篇文章记录了这个问题,

此时的resolve是处于图中第二行new Promise对象下调用的,所以this指向该promise,即上文记录的newP对象,而不是调用then的p1对象,

强调:此时newP状态为pending,data为undefined;
p1状态为resolved,data为1

8.
进入newP的resolve方法,改变pending为resolved,data为1,因为newP就是result
其实此时result结果就已经确定了,因为已经由结果了

9.
回到p1的then方法中进行后续任务,判断onResolved返回的数据是什么类型,此处不为promise类型,会进入else里面
resolve(result),这里的result不是newP,是onResolved的结果

9.
执行resolve方法,问题是此时是谁在调用该方法,可以在上图里看到,reslove是出于then方法中new 的Promise对象里的excutor的参数,this也被self暂存了,所以当此方法被调用时,并不是外部调用then方法的对象p1,而是这个新的promise对象,即上述记作insideP的对象,
强调:此时insideP为pending和undefined,
执行resolve后,insideP改变为resolved和1,

10.

接着第一次的onResolved循环结束,开始第二和第三次的循环,因为p2p3的异步onResolved都已经排在队列里了,后续都一样,
最终出来的result是在第8步就出了的结果。

【JS】Promise.race()方法例子流程详解相关推荐

  1. vue在created调用点击方法_vue.js中created方法的使用详解

    这次给大家带来vue.js中created方法的使用详解,使用vue.js中created方法的注意事项有哪些,下面就是实战案例,一起来看一下. 这是它的一个生命周期钩子函数,就是一个vue实例被生成 ...

  2. 多图上传以及多图排序的方法及流程详解

    多图上传以及多图排序的方法及流程详解 ps:本人亲测,阿里云2核4G5M的服务器性价比很高,新用户一块多一天,老用户三块多一天,最高可以买三年,感兴趣的可以戳一下:阿里云折扣服务器 所用插件包打包下载 ...

  3. Node.js 调用 C++ 方法 / C++ Addons 详解

    最近开发涉及到了一些Node.js调用C++的地方,于是网上搜了一下,发现网上好多文章都是比较片面的东西,没法直接使用.于是花点时间总结一下. Android开发中Java 调用C++的部分叫JNI, ...

  4. JS ES6中export和import详解

    1.Export 模块是独立的文件,该文件内部的所有的变量外部都无法获取.如果希望获取某个变量,必须通过export输出, // profile.js export var firstName = ' ...

  5. 基于spark mllib_Spark高级分析指南 | 机器学习和分析流程详解(下)

    - 点击上方"中国统计网"订阅我吧!- 我们在Spark高级分析指南 | 机器学习和分析流程详解(上)快速介绍了一下不同的高级分析应用和用力,从推荐到回归.但这只是实际高级分析过程 ...

  6. 杂志订阅管理系统c++_电池管理系统BMS功能安全开发流程详解

    点击上面 "电动知家"可以订阅哦! BMS功能安全开发流程详解 BMS和ISO26262 - BMS & ISO26262简介 BMS即Battery Management ...

  7. jenkins插件调用job_Jenkins迁移job插件Job Import Plugin流程详解

    Jenkins迁移job插件Job Import Plugin流程详解 由于又开了新机器所以又要重新布置Jenkins从老项目拷贝过来,发现Job Import Plugin 这个插件更新了,和以前的 ...

  8. 【联机对战】微信小程序联机游戏开发流程详解

    现有一个微信小程序叫中国象棋项目,棋盘类的单机游戏看着有缺少了什么,现在给补上了,加个联机对战的功能,增加了可玩性,对新手来说,实现联机游戏还是有难度的,那要怎么实现的呢,接下来给大家讲一下. 考虑到 ...

  9. JS弹出窗口Window.Open详解

    JS弹出窗口Window.Open详解 一.window.open()支持环境: JavaScript1.0+/JScript1.0+/Nav2+/IE3+/Opera3+ 二.基本语法: windo ...

最新文章

  1. 允许java运行不安全或不可信的应用程序
  2. PHP弱类型及一些绕过姿势
  3. Unity3D实践系列03,使用Visual Studio编写脚本与调试
  4. matlab mat文件 太大,MATLAB .mat文件中的开销过大
  5. k 近邻算法解决字体反爬手段|效果非常好
  6. JAVA I/O基本操作
  7. viper4android最新,ViPER4Android FX音效驱动下载-ViPER4Android音效驱动 v2.4.0.1 正式版_手机乐园...
  8. 一步一步安装服务器监视软件MRTG
  9. 当客户端浏览器不支持相应版本的apple时自动下载运行环境JVM的解决办法!
  10. 小一寸和一寸照片有区别吗 一寸照片怎么变成小一寸
  11. 条形码编码规则及标准
  12. rpm的安装与卸载,常用命令记载
  13. 10个最好的免费FTP客户端
  14. Javashop多用户商城系统源码 云表-无代码开发平台 框架源码
  15. 2018年 新年目标
  16. 西门子840d高级编程手册_斯沃系统手册--西门子高级编程手册_840D_810Di_810D_FM_NC高级篇.pdf...
  17. 中国丹参市场经营模式与盈利预测报告(新版)2021-2026年
  18. 2023年提高Google关键词排名的方法,如何提高谷歌排名?
  19. 机器学习实战- 回归(Regression) 概述
  20. HEX文件格式解析(转)

热门文章

  1. 比尔·盖茨的 33 年及名言集锦 - 为比尔送行、鼓掌!
  2. 串口调试助手读写三菱fx3u数据_用电脑通过串口(RS485)给三菱PLC(FX3U)发指令,怎样在梯形图里写接收串口数据的程序?...
  3. 小项目组迭代开发流程
  4. unity怎么显示骨骼_浅谈Unity3D 骨骼动画
  5. 2021-11-28第二周知识点
  6. 【杂谈】如何通过目标职位确定学习路径和努力方向(拿测试工程师举例子)
  7. C#实现ActiveX控件开发与部署---后记
  8. 刹车制动(卡钳)TOP3供应商份额超50%,哪些本土供应商突围
  9. 霍尼韦尔量子解决方案业务将与剑桥量子计算公司合并,打造全球最大最先进的量子计算企业...
  10. java双向链表详解