macrotask与microtask
在说明宏任务及微任务前总结一下事件循环机制(event loop):
- 首先判断JS是同步还是异步,同步就进入主线程,异步就进入event table
- 异步任务在event table中注册函数,当满足触发条件后,被推入event queue
- 同步任务进入主线程后一直执行,直到主线程空闲时,才会去event queue中查看是否有可执行的异步任务,如果有就推入主线程中
macrotask(宏任务):主代码块、setTimeout、setInterval等
microtask(微任务):Promise、process.nextTick等
下面通过【今日头条】这道面试题详细说明一下:
async function async1() {
console.log( 'async1 start' )
await async2()
console.log( 'async1 end' )
}
async function async2() {
console.log( 'async2' )
}
console.log( 'script start' )
setTimeout( function () {
console.log( 'setTimeout' )
}, 0 )
async1();
new Promise( function ( resolve ) {
console.log( 'promise1' )
resolve();
} ).then( function () {
console.log( 'promise2' )
} )
console.log( 'script end' )
先画一个通用任务表(后面的步骤就是给表插值的过程,执行顺序是从上至下,从左往右,先同步后异步)
| 宏任务1 | 宏任务2 | 宏任务3 | ... | 宏任务n |
|---|---|---|---|---|
| 微任务1.1 | 微任务2.1 | 微任务3.1 | ... | 微任务n.1 |
| 微任务1.2 | 微任务2.2 | 微任务3.2 | ... | 微任务n.2 |
| 微任务1.3 | 微任务2.3 | 微任务3.3 | ... | 微任务n.3 |
| ... | ... | ... | ... | ... |
步骤详解:
1、咱们整道面试题就是宏任务1,async1()及async2()函数声明先不管,直接看第一步执行的代码:console.log( 'script start' ),没有疑问,同步微任务。
| 面试题主代码块 | 宏任务2 | 宏任务3 | ... | 宏任务n |
|---|---|---|---|---|
| console.log( 'script start' ) | 微任务2.1 | 微任务3.1 | ... | 微任务n.1 |
| 微任务1.2 | 微任务2.2 | 微任务3.2 | ... | 微任务n.2 |
| 微任务1.3 | 微任务2.3 | 微任务3.3 | ... | 微任务n.3 |
| ... | ... | ... | ... | ... |
2、然后到setTimeout,一个新的宏任务,即宏任务2,其中函数执行代码console.log( 'setTimeout' )及该宏任务中的微任务。
| 面试题主代码块 | setTimeout | 宏任务3 | ... | 宏任务n |
|---|---|---|---|---|
| console.log( 'script start' ) | console.log( 'setTimeout' ) | 微任务3.1 | ... | 微任务n.1 |
| 微任务1.2 | 微任务2.2 | 微任务3.2 | ... | 微任务n.2 |
| 微任务1.3 | 微任务2.3 | 微任务3.3 | ... | 微任务n.3 |
| ... | ... | ... | ... | ... |
3、接下来是函数调用async1(),console.log( 'async1 start' )同步代码进入宏任务1。
| 面试题主代码块 | setTimeout | 宏任务3 | ... | 宏任务n |
|---|---|---|---|---|
| console.log( 'script start' ) | console.log( 'setTimeout' ) | 微任务3.1 | ... | 微任务n.1 |
| console.log( 'async1 start' ) | 微任务2.2 | 微任务3.2 | ... | 微任务n.2 |
| 微任务1.3 | 微任务2.3 | 微任务3.3 | ... | 微任务n.3 |
| ... | ... | ... | ... | ... |
4、随后执行await async2()语句,这里会先调用async2()中的同步代码,然后阻塞async1()的执行(直到该宏任务中所有同步代码执行完毕后再继续),具体原因可以参见我之前写的:async与await总结,所以async2()中同步代码console.log( 'async2' )进入宏任务1。
所以这里先把宏任务1中待执行的异步代码console.log( 'async1 end' )放最后面(其实是事件循环机制会在同步代码执行完毕即主线程空闲时,遍历一遍异步微任务,看是否有可执行的异步任务,有的话就推入主线程,我们人工怕遗留,所以先放后面):
| 面试题主代码块 | setTimeout | 宏任务3 | ... | 宏任务n |
|---|---|---|---|---|
| console.log( 'script start' ) | console.log( 'setTimeout' ) | 微任务3.1 | ... | 微任务n.1 |
| console.log( 'async1 start' ) | 微任务2.2 | 微任务3.2 | ... | 微任务n.2 |
| console.log( 'async2' ) | 微任务2.3 | 微任务3.3 | ... | 微任务n.3 |
| ... | ... | ... | ... | ... |
| console.log( 'async1 end' ) | ... | ... | ... | ... |
5、下面是执行new Promise(),Promise构造函数是直接调用的同步代码,所以将console.log( 'promise1' )加入宏任务1,但其中resolve()的执行为异步代码(实际为promise.then()的执行),所以将console.log( 'promise2' )依次放最后面:
| 面试题主代码块 | setTimeout | 宏任务3 | ... | 宏任务n |
|---|---|---|---|---|
| console.log( 'script start' ) | console.log( 'setTimeout' ) | 微任务3.1 | ... | 微任务n.1 |
| console.log( 'async1 start' ) | 微任务2.2 | 微任务3.2 | ... | 微任务n.2 |
| console.log( 'async2' ) | 微任务2.3 | 微任务3.3 | ... | 微任务n.3 |
| console.log( 'promise1' ) ) | 微任务2.4 | 微任务3.4 | ... | 微任务n.4 |
| ... | ... | ... | ... | ... |
| console.log( 'async1 end' ) | ... | ... | ... | ... |
| console.log( 'promise2' ) | ... | ... | ... | ... |
6、最后是console.log( 'script end' )同步代码的执行,放入宏任务1,同步之后,异步之前。
| 面试题主代码块 | setTimeout | 宏任务3 | ... | 宏任务n |
|---|---|---|---|---|
| console.log( 'script start' ) | console.log( 'setTimeout' ) | 微任务3.1 | ... | 微任务n.1 |
| console.log( 'async1 start' ) | 微任务2.2 | 微任务3.2 | ... | 微任务n.2 |
| console.log( 'async2' ) | 微任务2.3 | 微任务3.3 | ... | 微任务n.3 |
| console.log( 'promise1' ) ) | 微任务2.4 | 微任务3.4 | ... | 微任务n.4 |
| console.log( 'script end' ) | ... | ... | ... | ... |
| console.log( 'async1 end' ) | ... | ... | ... | ... |
| console.log( 'promise2' ) | ... | ... | ... | ... |
7、最后按照从上至下,从左往右的顺序执行就可以得到最终的结果了。
最终的打印顺序:
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout
参考资料:
1、8张图看清 async/await 和 promise 的执行顺序(原文中async1 end和promise2弄反了,需要注意):https://segmentfault.com/a/1190000017224799?_ea=5345525
macrotask与microtask的更多相关文章
- javascript中的异步 macrotask 和 microtask 简介
javascript中的异步 macrotask 和 microtask 简介 什么是macrotask?什么是microtask?在理解什么是macrotask?什么是microtask之前,我们先 ...
- 异步 JavaScript 之 macrotask、microtask
1.异步任务运行机制 先运行下面的一段代码: console.log('script start'); setTimeout(function() { console.log('setTimeout' ...
- 事件循环进阶:macrotask与microtask
这段参考了参考来源中的第2篇文章(英文版的),(加了下自己的理解重新描述了下), 这里没法给大家演示代码,我就简单说下我的理解吧. promise和settimeout 在一起的时候执行顺序是个有意思 ...
- 异步 JavaScript 之理解 macrotask 和 microtask(转)
这个知识点... https://blog.keifergu.me/2017/03/23/difference-between-javascript-macrotask-and-microtask/? ...
- JavaScript event loop事件循环 macrotask与microtask
macrotask 姑且称为宏任务,在很多上下文也被简称为task.例如: setTimeout, setInterval, setImmediate, I/O, UI rendering. mic ...
- JavaScript中的异步 macrotask 和 microtask
看过很多setTimeout.Promise执行顺序的面试题,一直不明白为啥都是异步操作,Promise就牛×些呢?直到了解了macrotask和micromask才恍然大悟... 先来一道面试题助助 ...
- 聊聊JavaScript异步中的macrotask和microtask
前言 首先来看一个JavaScript的代码片段: console.log(1); setTimeout(() => { console.log(2); Promise.resolve().th ...
- Javascript中的Microtask和Macrotask——从一道很少有人能答对的题目说起
首先我们来看一道题目,如下javascript代码,执行后会在控制台打印出什么内容? async function async1() { console.log('async1 start'); aw ...
- node的“宏任务(macro-task)”和“微任务(micro-task)”机制
macrotask 和 microtask 表示异步任务的两种分类.在挂起任务时,JS 引擎会将所有任务按照类别分到这两个队列中,首先在 macrotask 的队列(这个队列也被叫做 task que ...
随机推荐
- mac os catalina mongodb最新安装流程
1.brew安装 不推荐用brew,因为现在mongodb闭源了,brew里已经搜索不到mongodb,不过还是可以用brew安装的,这篇就不写了. 2.官网下载 直接去官网下载一个zip,解压完放到 ...
- CTF必备技能丨Linux Pwn入门教程——格式化字符串漏洞
Linux Pwn入门教程系列分享如约而至,本套课程是作者依据i春秋Pwn入门课程中的技术分类,并结合近几年赛事中出现的题目和文章整理出一份相对完整的Linux Pwn教程. 教程仅针对i386/am ...
- web文件上传的总结(二)改变Apache默认post值来提高文件上传大小
上传的文件大小大于2MB的解决方法 #默认apache 允许上大小2MB #技术经理-->修改apache默认配置 php.ini (授权) (1)复制 php.ini -> php1. ...
- 9.为什么要进行系统拆分?如何进行系统拆分?拆分后不用 dubbo 可以吗?
作者:中华石杉 面试题 为什么要进行系统拆分?如何进行系统拆分?拆分后不用 dubbo 可以吗? 面试官心理分析 从这个问题开始就进行分布式系统环节了,现在出去面试分布式都成标配了,没有哪个公司不问问 ...
- .net 4.0+ 应用接入openid Server步骤
.net 4.0+ 应用接入openid Server步骤: Requirements:Microsoft.AspNet.Mvc 5.2.4+ 1 确认应用是否是katana启动(项目引用了owin, ...
- 获取APK的appPackage和appActivity
[法二]AndroidSDK 此方法是采用AndroidSDK\build-tools\23.0.2(这个版本号可能不一定,但是一般每个版本号里面都,任意即可)\aapt.exe aapt dump ...
- zz开源 MNN:淘宝在移动 AI 上的实践
开源 MNN:淘宝在移动 AI 上的实践 陈以鎏(离青) 阅读数:40612019 年 6 月 28 日 随着深度学习的快速发展和端侧设备算力的不断提升,原本在云端执行的推理预测工作正在部分迁 ...
- 论文阅读笔记六十三:DeNet: Scalable Real-time Object Detection with Directed Sparse Sampling(CVPR2017)
论文原址:https://arxiv.org/abs/1703.10295 github:https://github.com/lachlants/denet 摘要 本文重新定义了目标检测,将其定义为 ...
- 生产者消费者模型-Java代码实现
什么是生产者-消费者模式 比如有两个进程A和B,它们共享一个固定大小的缓冲区,A进程产生数据放入缓冲区,B进程从缓冲区中取出数据进行计算,那么这里其实就是一个生产者和消费者的模式,A相当于生产者,B相 ...
- vue项目的安装与启动
第一步:安装Node 检测Node是否安装成功 node -v 第二步:安装vue-cli 命令:npm install vue-cli -g 第三步:搭建项目命令 vue init we ...