Promise魔鬼面试题
文章目录
- 题目
- 解析
- 难点分析
- 分析输出
- step1
- step2
- step3
- step4
- step5
- step6
参考/致谢:渡一袁老师
题目
Promise.resolve().then(() => {console.log(0);return Promise.resolve(4);}).then((res) => {console.log(res);});Promise.resolve().then(() => {console.log(1);}).then(() => {console.log(2);}).then(() => {console.log(3);}).then(() => {console.log(5);}).then(() => {console.log(6);});
解析
难点分析
-
这题难点就在于
return Promise.resolve(4)当返回一个 Promise 的时候是如何处理的,在 Promise a+ 规范中,写道,如图:
-
也就是说这个
当前Promise(表示return Promise了的当前这个Promise)要与返回的 Promise 保持一致,但是如何保持一致,标准里面并没有说到,也就说实际如何实现这个状态一致,并不关心,在 v8 中,实现的源码如图:
-
表示的意思是如果返回的是 Promise,它会去调用这个 Promise 的 then 方法,在这个 then 方法里面完成当前 Promsie,但是调用 then 方法完成当前这个 Promise 是会
放入到一个微任务队列里面去完成的 -
至此,这个难点就已经分析完成了
分析输出
step1
我们回到题目本身,来分析一下输出,我们知道,一个 then 方法一定会返回一个 Promise,then 方法是同步的,then 方法里面的回调才是异步的,根据这个准则,我们可以先来确定一下初步的执行状态。
根据这个准则,执行的初步顺序如下:
- 第一个 Promise.reslove():记作 pr1,状态为 fulfilled
- then(()=>{console.log(0)}):记作 p0,状态为 pending,因为这些then里面的回调函数还是异步任务,目前处于执行then方法的同步阶段,因此未执行也就无法确定 Promise 的状态,后续 pending 同理
- then((res)=>{console.log(res)}):记作 pres,状态为 pending
- 第二个 Promise.reslove():记作 pr2,状态为 fulfilled
- then(()=>{console.log(1)}):记作 p1,状态为 pending
- then(()=>{console.log(2)}):记作 p2,状态为 pending
- then(()=>{console.log(3)}):记作 p3,状态为 pending
- then(()=>{console.log(5)}):记作 p5,状态为 pending
- then(()=>{console.log(6)}):记作 p6,状态为 pending
图解如下:

step2
此时同步执行完成,只有两个 Promise 状态完成,这两个函数开始执行,首先就会输出 0,然后根据前面分析的规则,如果返回的是一个 Promise,就会调用这个 Promise的then方法,且是放入一个微队列中执行,这里的 Promise.resolve(4) 记作 p4,那么使用一个伪代码表示即为 addMicrotask(p4.then(()=>完成p0)),为什么是完成呢?这里的返回的事 Promise.resolve(),所以在 then 里面是完成 p0,演变图解如下:

step3
现在输出已经可以看到是 0,那么将微队列里面的任务开始执行,p1 的状态也会变为 fulfilled,然后将会输出 1,输出 1 之后
p1 变为 fulfilled 之后就会执行下一个 then 方法里面的成功回调,在这里也就是()=>{console.log(2)},而同理,这个回调也需要加入到微队列,即在 p4.then(()=>完成p0) 后加入
而 p4.then(()=>完成p0),其实需要执行只是()=>完成p0这一部分,then 方法里面的回调会加入到微队列,所以又会向后加入一个微任务,也就是在 ()=>{console.log(2)} 此回调后面,图解如下:

step4
我们继续分析执行结果,执行p4.then(),将里面的回调加入到微队列,那么就会按照顺序执行 console.log(2),p2 变为 fulfilled,紧接着输出 2,输出 2 之后,同理将 ()=>{console.log(3)} 加入到微队列
执行 ()=>完成p0,会将 p0 的状态也变为 fulfilled,p0 变为 fulfilled 之后,就会把 p0 后续的 then(即pres) 加入到微队列,图解如下:

step5
根据结果执行微队列里面的任务,同理 p3 也变为 fulfilled,然后就会输出 3,同时将 p3 下一个 then 方法的回调(即p5)加入到微队列。
然后执行 (res)=>{console.log(res)},同理 pres 状态为 fulfilled,控制台输出 4
res 为什么是 4?Promise a+ 规范,如果返回的是 promise,则下一个 then 方法的执行的回调和结果由这个返回的 Promise 决定,图解如下:

step6
那后续的输出就是一样的了,输出 5,同理 p5 的状态为 fulfilled,将 p6 的回调加入微队列,然后执行,输出 6,完成 p6,最后程序执行结果如图:

相关文章:
Promise魔鬼面试题
文章目录 题目解析难点分析分析输出step1step2step3step4step5step6 参考/致谢:渡一袁老师 题目 Promise.resolve().then(() > {console.log(0);return Promise.resolve(4);}).then((res) > {console.log(res);});Promise.resolve().then(() > {console.l…...
Vue3+Nuxt3 从0到1搭建官网项目(SEO搜索、中英文切换、图片懒加载)
Vue2Nuxt2 从 0 到1 搭建官网~ Vue3Nuxt3 从0到1搭建官网项目 安装 Nuxt3,创建项目初始化的 package.json项目结构初始化项目pages 文件下创建index.vue引入sass修改 app.vue 文件查看效果 配置公共的css、metaassets下的cssreset.scss 重置文件common.scss 配置nux…...
面试经典150题——三数之和
面试经典150题 day29 题目来源我的题解方法一 暴力解法 超时方法二 扩展两数之和(双指针)方法三 扩展为通用的n数之和 题目来源 力扣每日一题;题序:15 我的题解 方法一 暴力解法 超时 进行三重循环遍历,判断和是否为…...
go动态创建/增加channel并处理数据
背景描述 有一个需求,大概可以描述为:有多个websocket连接,因此消息会并发地发送过来,这些消息中有一个标志可以表明是哪个连接发来的消息,但只有收到消息后才能建立channel或写入已有channel,在收消息前无…...
asp.net成绩查询系统
说明文档 运行前附加数据库.mdf(或sql生成数据库) 主要技术: 基于asp.net架构和sql server数据库 功能模块: asp.net成绩查询系统 学生功能有查看成绩和修改账号密码等 后台管理员可以进行用户管理 管理员添加管理员查询注…...
Express路由
什么是路由 官方定义:路由确定了应用程序如何响应客户端对特定端点的请求。 路由的使用 一个路由的组成有 请求方法、路径 和 回调函数 组成。 Express中提供了一些列方法,可以很方便的使用路由,使用格式如下: app.<metho…...
在做题中学习(53): 寻找旋转数组中的最小值
153. 寻找旋转排序数组中的最小值 - 力扣(LeetCode) 解法:O(logn)->很可能就是二分查找 思路:再看看题目要求,可以画出旋转之后数组中元素的大小关系: 首先,数组是具有二段性的(适配二分查…...
C#语言进阶(三) 元组
总目录 C# 语法总目录 元组目录 元组1. 元组元素命名2. 元组的解构3. 元组的比较 元组 元组(tuple)是一组存储值的便捷方式。 元组的目的主要是,不使用out参数而从方法中返回多个值。(匿名类型无法做这个操作)元组能做匿名类型所有操作。 元组是值类型࿰…...
实用的Chrome 浏览器命令
Google Chrome 浏览器提供了许多快捷命令和实用功能,可以帮助用户提高效率和改善浏览体验。这里列举了一些非常实用的Chrome浏览器命令: 1. **CtrlT** / **CmdT** - 打开一个新的标签页。 2. **CtrlShiftT** / **CmdShiftT** - 重新打开最后关闭的标签页…...
IDEA远程连接docker服务,windows版docker desktop
1.windows上安装docker desktop docker desktop下载地址:Docker Desktop: The #1 Containerization Tool for Developers | Docker 有的windows系统不支持安装docker desktop 安装完之后我们可以直接打开,可以选择不登录使用 我们用IDEA连接到docker …...
Rust 和 Go 哪个更好?
在讨论 Rust 与 Go 两种编程语言哪种更优秀时,我们将探讨它们在性能、简易性、安全性、功能、规模和并发处理等方面的比较。同时,我们看看它们有什么共同点和根本的差异。现在就来看看这个友好而公平的对比。 Rust 和 Go 都是优秀的选择 首先ÿ…...
【免费Java系列】大家好 ,今天是学习面向对象高级的第八天点赞收藏关注,持续更新作品 !
这是java进阶课面向对象第一天的课程可以坐传送去学习http://t.csdnimg.cn/Lq3io day08-Map集合、Stream流、File类 一、Map集合 同学们,在前面几节课我们已经学习了Map集合的常用方法,以及遍历方式。 下面我们要学习的是Map接口下面的是三个实现类H…...
RPC 失败。curl 16 Error in the HTTP2 framing layer
报错: (base) hh-virtual-machine:~/work$ git clone https://github.com/yangzongzhuan/RuoYi-Vue3.git 正克隆到 RuoYi-Vue3... error: RPC 失败。curl 16 Error in the HTTP2 framing layer fatal: 在引用列表之后应该有一个 flush 包这个错误通常是由于 Git 在…...
(图论)最短路问题合集(包含C,C++,Java,Python,Go)
不存在负权边: 1.朴素dijkstra算法 原题: 思路:(依然是贪心的思想) 1.初始化距离:dis[1]0,dis[i]INF(正无穷) 2.循环n次: 找到当前不在s中的dis最小的点&…...
电脑文件批量重命名不求人:快速操作,高效技巧让你轻松搞定
在数字化时代,电脑文件的管理与整理显得尤为重要。当面对大量需要重命名的文件时,一个个手动修改不仅耗时,还容易出错。那么,有没有一种方法可以快速、高效地完成这一任务呢?答案是肯定的,下面就来介绍几种…...
基于springboot的网上点餐系统源码数据库
基于springboot的网上点餐系统源码数据库 随着科学技术的飞速发展,各行各业都在努力与现代先进技术接轨,通过科技手段提高自身的优势;对于网上点餐系统当然也不能排除在外,随着网络技术的不断成熟,带动了网上点餐系统…...
mysql cluster数据库集群介绍、部署及配置
前言: MySQL集群是一个无共享的、分布式节点架构的存储方案,旨在提供容错性和高性能。它由三个主要节点组成:管理节点(MGM)、数据节点和SQL节点。 管理节点(MGM) 定义与用途:管理节点是MySQL Cluster的控制中心,负责管理集群内的其他节点。它提供配置数据,启动和停止…...
uniapp的app端软件更新弹框
1:使用html PLUS实现:地址HTML5 API Reference (html5plus.org),效果图 2:在app.vue的onLaunch生命周期中,代码如下: onLaunch: function() {let a 0let view new plus.nativeObj.View(maskView, {backg…...
win11 Terminal 部分窗口美化
需求及分析:因为在 cmd、anaconda prompt 窗口中输入命令较多,而命令输入行和输出结果都是同一个颜色,不易阅读,故将需求定性为「美化窗口」。 美化结束后,我在想是否能不安装任何软件,简单地通过调整主题颜…...
开源go实现的iot物联网新基建平台
软件介绍 Magistrala IoT平台是由Abstract Machines公司开发的创新基础设施解决方案,旨在帮助组织和开发者构建安全、可扩展和创新的物联网应用程序。曾经被称为Mainflux的平台,现在已经开源,并在国际物联网领域受到广泛关注。 功能描述 多协…...
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区。编辑器中应用变更时的操作范围,就是以模型选区为基准来…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险
C#入门系列【类的基本概念】:开启编程世界的奇妙冒险 嘿,各位编程小白探险家!欢迎来到 C# 的奇幻大陆!今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类!别害怕,跟着我,保准让你轻松搞…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...
Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)
引言 在人工智能飞速发展的今天,大语言模型(Large Language Models, LLMs)已成为技术领域的焦点。从智能写作到代码生成,LLM 的应用场景不断扩展,深刻改变了我们的工作和生活方式。然而,理解这些模型的内部…...
C++ 设计模式 《小明的奶茶加料风波》
👨🎓 模式名称:装饰器模式(Decorator Pattern) 👦 小明最近上线了校园奶茶配送功能,业务火爆,大家都在加料: 有的同学要加波霸 🟤,有的要加椰果…...
Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案
在大数据时代,海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构,在处理大规模数据抓取任务时展现出强大的能力。然而,随着业务规模的不断扩大和数据抓取需求的日益复杂,传统…...
上位机开发过程中的设计模式体会(1):工厂方法模式、单例模式和生成器模式
简介 在我的 QT/C 开发工作中,合理运用设计模式极大地提高了代码的可维护性和可扩展性。本文将分享我在实际项目中应用的三种创造型模式:工厂方法模式、单例模式和生成器模式。 1. 工厂模式 (Factory Pattern) 应用场景 在我的 QT 项目中曾经有一个需…...
全面解析数据库:从基础概念到前沿应用
在数字化时代,数据已成为企业和社会发展的核心资产,而数据库作为存储、管理和处理数据的关键工具,在各个领域发挥着举足轻重的作用。从电商平台的商品信息管理,到社交网络的用户数据存储,再到金融行业的交易记录处理&a…...
