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

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)

【面试题】宏任务和微任务_第1张图片

2. enevt loop和DOM渲染

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

当Call Stack中的同步代码全部执行完毕之后,会进行DOM渲染,然后再触发event loop。
【面试题】宏任务和微任务_第2张图片
实例:当点击alert弹框的确认按钮后,才会渲染DOM元素,因为不点击确认按钮,Call Stack中的代码不会清空,就不会进行下一步:DOM渲染。

<body>
    <div id="container"></div>
    <script>
        
        const $p1 = $('

一段文字

'
) const $p2 = $('

一段文字

'
) const $p3 = $('

一段文字

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

【面试题】宏任务和微任务_第3张图片

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

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

一段文字

'
) const $p2 = $('

一段文字

'
) const $p3 = $('

一段文字

'
) $('#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>

【面试题】宏任务和微任务_第4张图片

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

  可以从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渲染后执行,因此微任务的执行早于宏任务。
【面试题】宏任务和微任务_第5张图片

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

【面试题】宏任务和微任务_第6张图片

你可能感兴趣的:(面试题,javascript,前端,开发语言)