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 ...
随机推荐
- day09 作业
简述定义函数的三种方式 空函数.无参函数.有参函数 简述函数的返回值 函数内部代码经过一系列的逻辑处理返回的结果 函数没有返回值,默认返回None 函数可以通过return返回出返回值 return可 ...
- liteos时间管理(九)
1. 时间管理 1.1 概述 1.1.1 概念 时间管理以系统时钟为基础.时间管理提供给应用程序所有和时间有关的服务. 系统时钟是由定时/计数器产生的输出脉冲触发中断而产生的,一般定义为整数或长整数. ...
- JavaWeb项目 IDEA+Tomcat+Nginx 部署流程
转载请注明原文地址:https://www.cnblogs.com/ygj0930/p/11375100.html 一:IDEA Maven项目打包 1.修改打包方式 在maven项目的pom文件中, ...
- 安装教程-VMware 12 安装企业级 CentOS 7.6
企业级 CentOS 7.6 系统的安装 1.实验描述 在虚拟机中,手动安装 CentOS 7.6 操作系统,为学习 Linux 提供平台,因此,有的参数有些差异,请勿较真. 2.实验环境 物理机系统 ...
- 【洛谷P3756】[CQOI2017]老C的方块(最小割)
洛谷 题意: 给出一个网格图类似于这样: 现在给出一个\(n*m\)大小的网格,之后会给出一些点,若某些点相连形成了如下的几个图案,那么就是不好的. 现在可以删去一些点,但删除每个点都有一些代价,问最 ...
- 剖析linux内核中的宏---------container_of
#define container_of(ptr, type, member) ({ \ const typeof(((type *)0)->member) * __mptr = (ptr); ...
- C#基础操作符详解(下)
书接上文的基本操作符,下文介绍的是其他操作符: 4.2一元操作符: 只要有一个操作数跟在它后面就可以构成表达式,也叫单目操作符. ①&x和*x操作符(很少见有印象即可): 这两个操作符同样也需 ...
- 283.移动零 关于列表list与remove原理*****(简单)
题目: 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序. 注意,该题目要求不开辟行的数组空间,在原数据上进行操作. 示例: 输入: [0,1,0,3,12 ...
- 01-人脸识别-基于MTCNN,框选人脸区域-detect_face_main
(本系列随笔持续更新) 搭建要求 详细的搭建过程在 参考资料1 中已经有啦. TensorFlow 1.6.0 OpenCV 2.4.8 仅仅是加载和读取图片的需要 Ubuntu 14.04 64bi ...
- 莫烦TensorFlow_06 plot可视化
import tensorflow as tf import numpy as np import matplotlib.pyplot as plt def add_layer(inputs, in_ ...