zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    一个好用的,个人记事本应用,软件joplin
    aws EKS EFS 上安装mysql Operation notpermitted
    多变量的线性回归
    批量梯度下降BGD、随机梯度下降SGD和小批量梯度下降MBGD对比
    单变量线性回归
    数据库限制内存使用方法
    C# 调用 Excel 宏的方法
    Markdown 使用方法总结
    VBA注意事项
    将CSV文件中的数据导入到SQL Server 数据库中
  • 原文地址:https://www.cnblogs.com/dreamsqin/p/11979400.html
Copyright © 2011-2022 走看看