在说明宏任务及微任务前总结一下事件循环机制(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的更多相关文章

  1. javascript中的异步 macrotask 和 microtask 简介

    javascript中的异步 macrotask 和 microtask 简介 什么是macrotask?什么是microtask?在理解什么是macrotask?什么是microtask之前,我们先 ...

  2. 异步 JavaScript 之 macrotask、microtask

    1.异步任务运行机制 先运行下面的一段代码: console.log('script start'); setTimeout(function() { console.log('setTimeout' ...

  3. 事件循环进阶:macrotask与microtask

    这段参考了参考来源中的第2篇文章(英文版的),(加了下自己的理解重新描述了下), 这里没法给大家演示代码,我就简单说下我的理解吧. promise和settimeout 在一起的时候执行顺序是个有意思 ...

  4. 异步 JavaScript 之理解 macrotask 和 microtask(转)

    这个知识点... https://blog.keifergu.me/2017/03/23/difference-between-javascript-macrotask-and-microtask/? ...

  5. JavaScript event loop事件循环 macrotask与microtask

    macrotask  姑且称为宏任务,在很多上下文也被简称为task.例如: setTimeout, setInterval, setImmediate, I/O, UI rendering. mic ...

  6. JavaScript中的异步 macrotask 和 microtask

    看过很多setTimeout.Promise执行顺序的面试题,一直不明白为啥都是异步操作,Promise就牛×些呢?直到了解了macrotask和micromask才恍然大悟... 先来一道面试题助助 ...

  7. 聊聊JavaScript异步中的macrotask和microtask

    前言 首先来看一个JavaScript的代码片段: console.log(1); setTimeout(() => { console.log(2); Promise.resolve().th ...

  8. Javascript中的Microtask和Macrotask——从一道很少有人能答对的题目说起

    首先我们来看一道题目,如下javascript代码,执行后会在控制台打印出什么内容? async function async1() { console.log('async1 start'); aw ...

  9. node的“宏任务(macro-task)”和“微任务(micro-task)”机制

    macrotask 和 microtask 表示异步任务的两种分类.在挂起任务时,JS 引擎会将所有任务按照类别分到这两个队列中,首先在 macrotask 的队列(这个队列也被叫做 task que ...

随机推荐

  1. webpack加载css文件及其配置

    webpack加载css文件及其配置 当我们写了几个css文件之后如果想要引用到html中去的话我们最开始的方式就是通过link标签将css文件导入进去,但是如果我们的css文件有很多的话,一个个的导 ...

  2. Tests in error:BlogApplicationTests.initializationError » IllegalState Unable to find a @Spri...【解决】

    刚刚写完一个项目,准备打包,却发现无法打包. 然后认真排查了一下问题.发现少引入了一个插件. <plugin> <groupId>org.apache.maven.plugin ...

  3. windows 下 创建项目的虚拟环境

    一. 为何使用虚拟环境 虚拟环境是Python解释器的一个私有副本,在这个环境你可以安装私有包,而且不会影响系统中安装的全局Python解释器. 在这个虚拟环境中的所有安装包,都是针对此环境的,不会被 ...

  4. failed to map segment from shared object: Permission denied(error while loading shared libraries: libz.so.1)

    centos 6.3 服务器重启后,sshd 竟然连接不上了,防火墙也没有限制,重启sshd 服务报以下错误: 于是到/lib64 目录下找,库文件并没有少,仔细想后面的报错信息是权限被拒绝了,百度了 ...

  5. git仓库的安装和基本使用

    一.安装git软件 # yum install git -y 二.初始化git仓库 2.1 在git仓库的机器进行配置 # ifconfig eth0 | awk -F '[ :]+' 'NR==2 ...

  6. Win7共享只看到部分文件

    把192.168.70.88这台机器的Android目录做为共享文件夹. 共享端:windows server 用户端:其它pc机安装windows7 或windows 10 在用户端只能看到部分文件 ...

  7. flask 案例项目基本框架的搭建

    综合案例:学生成绩管理项目搭建 一 新建项目目录students,并创建虚拟环境 mkvirtualenv students 二 安装开发中使用的依赖模块 pip install flask==0.1 ...

  8. android 开发工具 adb

    1.abd基本使用 1.启动一个adb应用程序 adb -P <port> start-server # -P指定端口 默认是5037 1.停止adb adb kill-server 2. ...

  9. LeetCode 120. Triangle三角形最小路径和 (C++)

    题目: Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjace ...

  10. zzulioj - 2600: 有多少天?

    题目链接:http://acm.zzuli.edu.cn/problem.php?id=2600 题目描述 小D同学对日期类的问题很是有兴趣,已知1900-01-01是星期一,那么小D想知道给定两个年 ...