【面试题】宏任务和微任务

2023-11-19

1. 宏任务和微任务

宏任务(macroTask)和微任务(microTask)都是异步中API的分类。

  • 宏任务:setTimeout,setInterval,Ajax,DOM事件
  • 微任务:Promise,async/await

微任务执行时机比宏任务要早。

 console.log(100)
 // 宏任务
 setTimeout(()=>{
     console.log(200)
 })
 // 微任务
 Promise.resolve().then(()=>{
     console.log(300)
 })
 console.log(400)

在这里插入图片描述

2. enevt loop和DOM渲染

JS是单线程的,而且和DOM渲染公用一个线程。JS执行的时候,需要留出时机用于DOM渲染。这个时机就是微任务执行后,宏任务执行前。

当Call Stack中的同步代码全部执行完毕之后,会进行DOM渲染,然后再触发event loop。
在这里插入图片描述
实例:当点击alert弹框的确认按钮后,才会渲染DOM元素,因为不点击确认按钮,Call Stack中的代码不会清空,就不会进行下一步:DOM渲染。

<body>
    <div id="container"></div>
    <script>
        
        const $p1 = $('<p>一段文字</p>')
        const $p2 = $('<p>一段文字</p>')
        const $p3 = $('<p>一段文字</p>')

        $('#container')
                    .append($p1)
                    .append($p2)
                    .append($p3)

        
        console.log('length', $('#container').children().length)
        alert('本次 call stack 结束,DOM 结构已更新,但尚未触发渲染')    // alert会阻断js执行,也会阻断DOM渲染
        
    </script>
</body>

请添加图片描述

3. 宏任务和微任务的根本区别

  • 宏任务:DOM渲染后触发,如setTimeout
  • 微任务:DOM渲染前触发,如Promise
<body>
    <div id="container"></div>
    <script>
        const $p1 = $('<p>一段文字</p>')
        const $p2 = $('<p>一段文字</p>')
        const $p3 = $('<p>一段文字</p>')

        $('#container')
            .append($p1)
            .append($p2)
            .append($p3)

        // 微任务:DOM渲染前触发
        Promise.resolve().then(()=>{
            console.log('lenght1', $('container').children().length)
            alert('触发了微任务')
        })

        // 宏任务:DOM渲染后触发
        setTimeout(()=>{
            console.log('lenght2', $('container').children().length)
            alert('触发了宏任务')
        })
    </script>
</body>

请添加图片描述

为什么微任务执行会更早?

  可以从event loop去理解。假如程序执行的时候遇到宏任务,例如setTimeout,此时会将setTimeout中执行的代码放入Web APIs中,等到所有的同步代码执行完,以及DOM元素渲染完毕之后,执行event loop,此时Web APIs中的代码等到了时机,会移动到Callback Queue中,event loopCallback Queue中的代码移到Call Stack中执行。
  然而,当Call Stack中遇到微任务时,例如Promise,此时会将Promise执行的代码放入micro task queue。因为Promise是ES6规定的,不是W3C规定的,因此执行时放入micro task queuemicro task queue的执行是先于DOM渲染的。微任务在DOM渲染前执行,宏任务在DOM渲染后执行,因此微任务的执行早于宏任务。
在这里插入图片描述

4. 实例

JS代码执行的顺序:

  1. 首先执行同步代码;
  2. 同步代码执行结束后,call stack被清空,开启envet loop;
  3. 执行微任务;
  4. 触发DOM元素渲染;
  5. 触发enevt loop;
  6. 执行宏任务。
async function async1(){
    console.log('async1 start')   // 顺序2
    await async2()
    console.log('async1 end')    // 顺序6
}

async function async2(){
    console.log('async2')      // 顺序3
}

console.log('script start')     // 顺序1

setTimeout(function(){
    console.log('setTimeout')   // 顺序8
}, 0)

async1()

// 初始化 promise 时,传入的函数会立刻被执行
new Promise(function(resolve){
    console.log('promise1')        // 顺序4
    resolve()
}).then(function(){
    console.log('promise2')    // 顺序7
})

console.log('script end')    // 顺序5

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【面试题】宏任务和微任务 的相关文章