【面试题】async/await、promise和setTimeout的执行顺序

news2025/1/16 6:51:39

从一道题目出发

今天看到一道面试题,是关于async/await、promise和setTimeout的执行顺序,题目如下:

asyncfunctionasync1() {
	console.log('async1 start');
	awaitasync2();
	console.log('asnyc1 end');
}
asyncfunctionasync2() {
	console.log('async2');
}
console.log('script start');
setTimeout(() => {
	console.log('setTimeOut');
}, 0);
async1();
newPromise(function (reslove) {
	console.log('promise1');
	reslove();
}).then(function () {
	console.log('promise2');
})
console.log('script end');
复制代码

我给出的答案:

script start
async1 start
async2
asnyc1 end// x
promise1
script end
promise2
setTimeOut
复制代码

正确的答案:

script start
async1 start
async2
promise1
script end
asnyc1 end
promise2
setTimeOut
复制代码

为什么promise1比asnyc1 end先出来呢?带着这个疑问,我去了解了一下事件循环机制

js EventLoop 事件循环机制

JavaScript的事件分两种:

宏任务(macro-task)

微任务(micro-task)

script

promise.[ then/catch/finally ]((非new Promise))

setTimeout

process.nextTick(Node.js 环境)

setInterval

MutaionOberver(浏览器环境)

setImmediate(Node.js 环境)

Object.observe

IO操作

x

UI交互事件

x

postMessage

x

MessageChannel

x

事件的执行顺序,是先执行宏任务,然后执行微任务,这个是基础,任务可以有同步任务和异步任务,同步的进入主线程,异步的进入Event Table并注册函数,异步事件完成后,会将回调函数放入Event Queue中(宏任务和微任务是不同的Event Queue),同步任务执行完成后,会从Event Queue中读取事件放入主线程执行,回调函数中可能还会包含不同的任务,因此会循环执行上述操作。

注意: setTimeOut并不是直接的把你的回掉函数放进上述的异步队列中去,而是在定时器的时间到了之后,把回掉函数放到执行异步队列中去。如果此时这个队列已经有很多任务了,那就排在他们的后面。这也就解释了为什么setTimeOut为什么不能精准的执行的问题了。setTimeOut执行需要满足两个条件:
主进程必须是空闲的状态,如果到时间了,主进程不空闲也不会执行你的回调函数
这个回调函数需要等到插入异步队列时前面的异步函数都执行完了,才会执行

promise、async/await

首先,new Promise是同步的任务,会被放到主进程中去立即执行。而.then()函数是异步任务会放到异步队列中去,那什么时候放到异步队列中去呢?当你的promise状态结束的时候,就会立即放进异步队列中去了。

带async关键字的函数会返回一个promise对象,如果里面没有await,执行起来等同于普通函数;如果没有await,async函数并没有很厉害是不是。

await 关键字要在 async 关键字函数的内部,await 写在外面会报错;await如同他的语意,就是在等待,等待右侧的表达式完成。此时的await会让出线程,阻塞async内后续的代码,先去执行async外的代码。等外面的同步代码执行完毕,才会执行里面的后续代码。就算await的不是promise对象,是一个同步函数,也会等这样操作。

流程梳理

我们整体再梳理一下上面代码执行的流程:

整个代码片段(script)作为一个宏任务执行console.log('script start'),输出script start;
执行setTimeout,是一个异步动作,放入宏任务异步队列中;
执行async1(),输出async1 start,继续向下执行;
执行async2(),输出async2,并返回了一个promise对象,await让出了线程,把返回的promise加入了微任务异步队列,所以async1()下面的代码也要等待上面完成后继续执行;
执行 new Promise,输出promise1,然后将resolve()放入微任务异步队列;
执行console.log('script end'),输出script end;
到此同步的代码就都执行完成了,然后去微任务异步队列里去获取任务
接下来执行resolve(async2返回的promise返回的),输出了async1 end;
然后执行resolve(new Promise的),输出了promise2;
最后执行setTimeout,输出了settimeout。

在第4步中, await 这里有一个机制, 就是 await 的等待, 不会阻塞外部函数的执行, 而 await 等待的 如果是一个 Promise 则 Promise 里面的代码还是同步执行, 如果不是 Promise ,就会使用 Promise.resolve 来进行封装, 这里的 async2 是一个 async 方法, 里面的 打印会同步执行, 而 await async2() 后面的代码 会放到微任务队列中的第一个位置,等待外部同步代码执行完毕以后再执行。

所以我知道了script end为什么会优先于async1 end输出。

大厂面试题分享 面试题库

前端面试题库 (面试必备) 推荐:★★★★★

地址:前端面试题库

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/198216.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

kafka官方文档中文翻译(kafka参数解释)

目录 入门 1.1简介 kafka™是一个分布式流媒体平台。这到底意味着什么? 1.2使用案例 1.3快速入门 1.4生态系统 1.5从以前的版本升级 2. API 2.1生产者API 2.2消费者API 2.3 Streams API 2.4连接API 2.5遗留API 3.配置 3.1Broker配置 3.2生产者配置 …

Exynos 4412 看门狗定时器中断

如果想弄懂看门狗定时器中断,要掌握下面两个知识点: 1 懂寄存器 Cortex A9采用的是ARM官方规定的中断处理机制 有两大类寄存器决定了中断工作状态 1) exynos 4412 特有的寄存器(在第26章) 2) Cortex A9 规定的工作寄存器(在第9章和第10章) 2 懂中断处理过…

【memcached】下载、安装、、出错一分钟全搞定

各位小伙伴在看黑马程序员springboot的时候可能会遇到的情况:memcached如何安装?官网地址:https://www.runoob.com/memcached/window-install-memcached.html找到合适的下载即可,占用内容很小,几秒就下载好了开启服务安…

SpringBoot + jackson + redis 序列化、反序列化 配置正确姿势

文章目录1.背景2. 原来项目配置3.正确配置4.小结1.背景 最近项目上 使用 SpringBoot 2.7.7 jackson redis 框架实现将javaBean 序列化和反序列化到 redis 中。但是最近在做登陆的时候将LoginUser 序列化到redis 中没问题,不重启服务的话反序列化成对象也没有问题…

【Java多线程】同步代码块处理线程安全问题

题:创建三个窗口卖票,总票数为100张 1.问题:买票过程中,出现了重票,错票 --> 出现了线程的安全问题 2.问题出现的原因:当某个线程操作车票的过程中,尚未操作完成时,其他线程参与进…

IDEA常用技巧汇总

查看代码历史版本鼠标在需要查看的java类 右键 找到Local History >> Show History 点开即可看到历史版本,常用于自己忘记代码改了哪些内容 或需要恢复至某个版本 (注意 只能看近期修改 太久了也是看不到的)idea设置成eclipse的快捷键这对eclipse转idea的开发…

网络编程套接字

✏️作者:银河罐头 📋系列专栏:JavaEE 🌲“种一棵树最好的时间是十年前,其次是现在” 目录Socket 套接字UDP 和 TCPUDP数据报套接字编程DatagramSocket APIDatagramPacket APIUdpEchoServerUdpEchoClientUdpDictServer…

分享62个JS返回顶部特效,总有一款适合您

分享62个JS返回顶部特效,总有一款适合您 62个JS返回顶部特效下载链接:https://pan.baidu.com/s/1X1fSwxibtEDXKeYqj0sHXQ?pwde2kp 提取码:e2kp Python采集代码下载链接:https://wwgn.lanzoul.com/iKGwb0kye3wj import os im…

[Android]Toolbar

Toolbar是由AndroidX库提供的,它的强大之处在于,它不仅继承了ActionBar的所有功能,并且灵活度很高,可以配合其他控件完成一些Material Design的效果。 使用Toolbar替代ActionBar 在themes的两个xml文件中, 都指定一个…

视频连载08 - 这个为生信学习和生信作图打造的开源R教程真香!!!

点击阅读原文跳转完整教案。1 思考题2 R基础2.1 R安装2.2 Rstudio基础2.2.1 Rstudio版本2.2.2 Rstudio安装2.2.3 Rstudio 使用2.3 R基本语法2.3.1 获取帮助文档,查看命令或函数的使用方法、事例或适用范围2.3.2 R中的变量及其初始化2.3.3 变量类型和转换2.3.4 R中矩…

ECharts接收dataset类型数据封装各类型图形组件

数据平台整合matabase图表,调用matabase已有接口使用echarts实现图表展示 目标 将各类型图形独立封装为组件 将多个组件整体封装成一个组件 使用时只需传入组件名和对应数据即可 展示 数据格式 ECharts中dataset配置 公共组件 示例饼图 pie-chart pie-chart comm…

AcWing 1083. Windy数(数位DP)

AcWing 1083. Windy数(数位DP)一、问题二、分析状态表示状态转移初末状态循环设计注意事项三、代码一、问题 二、分析 这道题考察的是数位DP的知识,对于数位DP的分析方法作者在之前的文章中做过详细地介绍:AcWing 1081. 度的数量…

java面试题(九)集合篇

2.1 Java中有哪些容器(集合类)? 参考答案 Java中的集合类主要由Collection和Map这两个接口派生而出,其中Collection接口又派生出三个子接口,分别是Set、List、Queue。所有的Java集合类,都是Set、List、Qu…

【LeetCode】Day206-二叉树着色游戏

题目 1145. 二叉树着色游戏【中等】 题解 官解说的实在是抽象了,看了下高赞题解,果然很清晰易懂 以 x 为根,它的三个邻居(左儿子、右儿子和父节点)就对应着三棵子树: 左子树右子树父节点子树 哪棵子树…

微服务项目框架及多模块开发

目录 项目模式 技术栈 项目架构图 模块 案例演示 主模块 zmall-common子模块 zmall-user子模块 项目模式 电商模式:市面上有5种常见的电商模式,B2B、B2C、 C2B、 C2C、O2O; 1、B2B模式 B2B (Business to Business),是指 商家与商家…

java递归-八皇后问题(回溯算法)

1.八皇后问题介绍 八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯贝瑟尔于 1848 年提出:在 88 格的国际象棋上摆放八个皇后,使其不能互相攻击,即:任意两个皇后都…

Day04-数据分析模型

文章目录数据分析模型数据分析流程第一:定性法第二:定量法一、数据分析要解决什么问题?1. 研究历史2. 解释现状4. 洞察商机5. 寻求最佳方案二、数据分析师的工作三、数据分析流程1. 数据分析框架2. 数据获取3. 数据处理4. 数据分析5. 撰写报告…

大数据技术架构(组件)18——Hive:FileFormats(1)

1.5、FileFormats1.5.1、FileFormat对比:1.5.1.1、Text File每一行都是一条记录,每行都以换行符(\ n)结尾。数据不做压缩,磁盘开销大,数据解析开销大。可结合Gzip、Bzip2使用(系统自动检查&…

Python 3 基本数据类型,包含示例演示(初学友好)

嗨害大家好鸭~ 我是小熊猫 有好好学习python吗? Python学习资料电子书 点击此处跳转文末名片获取 Python3 基本数据类型 Python 中的变量不需要声明。每个变量在使用前都必须赋值,变量赋值以后该变量才会被创建。 在 Python 中,变量就是变量…

Redis实现分布式锁

基于Redis实现分布式锁。分为单Redis节点实现和Redis集群实现。 基于单个Redis节点实现分布式锁 作为分布式锁实现过程中的共享存储系统,Redis可以使用键值对来保护锁变量,在接收和处理不同客户端发送的加锁的操作请求。 客户端A、C同时请求加锁&#…