微任务与宏任务

157 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第三天,点击查看活动详情

前言

上一篇文章我们讲了js的执行流程和事件循环机制,我们接着上面的再来讲一下es标准中新引入的微任务跟宏任务。读完之后相信后面在遇到类似微任务与宏任务的面试题你就会觉得这不是1+1=2那么简单的题吗。

1. 什么是微任务和宏任务

1.1 微任务

  • process.nextTick
  • Promise.then catch finally
  • MutationObserver

1.2 宏任务

  • setTimeout
  • setInterval
  • setImmediate
  • requestAnimationFrame
  • script(可以理解为最外层的同步代码)

微任务的执行优先级要比宏任务高,在事件循环的时候当js的主线程执行栈没有东西执行去任务队列找任务执行的时候,此时会有两个任务队列(微任务的任务队列,宏任务的任务队列),这时候会先去执行微任务任务队列中的函数,直到没有了才会去执行宏任务的任务队列。

上一章我们讲了就一个任务队列 现在就是区分开了 。

2.解析

上面的图看不明白的话 我们来看个小列子,画图演示一下

<script>
  setTimeout(() => {
      //执行后 回调一个宏事件
      console.log('内层宏事件3')
  }, 0)
  console.log('外层宏事件1');

  new Promise((resolve) => {
      console.log('外层宏事件2');
      resolve()
  }).then(() => {
      console.log('微事件1');
  }).then(()=>{
      console.log('微事件2')
  })
</script>

打印结果

外层宏事件1
外层宏事件2
微事件1
微事件2
内层宏事件3

可能有的小伙伴不知道为啥打印的是这个结果,不要慌我们先分析图中有哪些微任务和宏任务

微任务:promise.then()有两个

宏任务:setTimeout(),script

同步:console.log() new Promise()

分析好之后我们模拟开始执行

执行最外层宏任务script接着遇到setTimeout()宏任务交给setTimeout线程处理完后放入宏任务任务队列,遇到同步任务console.log('外层宏事件1');直接执行接着遇到new Promise()执行console.log('外层宏事件2');然后遇到resolve() 发现.then()交给异步线程处理完后放入微任务队列。此时最外层script宏任务执行结束去看看微任务队列有没有任务,发现了console.log('微事件1');,console.log('微事件2') 微任务队列没有任务之后再去宏任务队列中去找任务发现了 console.log('内层宏事件3')此时都没任务了执行结束

画图

1.js主线程执行遇到异步任务告诉eventLoop让异步线程去执行任务

2.eventLoop告诉异步线程主线给你的异步任务你快执行

3.异步线程告诉eventLoop我执行完了你放入任务队列吧

eventLoop 根据不同的任务类型放入不同的队列

4.微任务中有微任务立马返回执行

5.执行栈空了之后再去微任务中找任务 如果没有了就回去宏任务中找任务有任务立即返回执行。

重复循环

3.练习题

//主线程直接执行
console.log('1');
//丢到宏事件队列中
setTimeout(function() {
    console.log('2');
    process.nextTick(function() {
        console.log('3');
    })
    new Promise(function(resolve) {
        console.log('4');
        resolve();
    }).then(function() {
        console.log('5')
    })
})
//微事件1
process.nextTick(function() {
    console.log('6');
})
//主线程直接执行
new Promise(function(resolve) {
    console.log('7');
    resolve();
}).then(function() {
    //微事件2
    console.log('8')
})
//丢到宏事件队列中
setTimeout(function() {
    console.log('9');
    process.nextTick(function() {
        console.log('10');
    })
    new Promise(function(resolve) {
        console.log('11');
        resolve();
    }).then(function() {
        console.log('12')
    })
})

执行结果:完整的输出为1,7,6,8,2,4,3,5,9,11,10,12。

根据这个题目你们也去做个笔记吧 会让你们的理解更加深刻。

总结

不要想着一步登天,打肿脸充胖子,不懂就去学从最基础的学,这样你的脑子中才会有一张蓝图,告诉你该怎么做,不然你的脑子中会出现各种分叉路说不定下一步就是错的,你的面试也就终结了。