【事件循环】宏任务和微任务

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

JavaScript 的异步任务根据事件分类分为两种:宏任务(MacroTask)和微任务(MicroTask)

  • 宏任务: main script、setTimeout、setInterval、setImmediate(Node.js)、I/O(Mouse Events、Keyboard Events、Network Events)、UI Rendering(HTML Parsing)、MessageChannel
  • 微任务: Promise.then(非 new Promise)、process.nextTick(Node.js)、MutationObserver
  • 宏任务和微任务的区别在于队列中事件的执行优先级。

2、宏任务和微任务的优先级

  • 宏任务的优先级高于微任务(有的博客或网站会说微任务优先级高于宏任务,这个看自己的理解了,但是最终的执行顺序是一致的,如果不相信可以继续往后看
  • 每个宏任务执行完毕后都必须将当前的微任务队列清空,接着执行下一个宏任务
  • 第一个 “script” 标签的代码是第一个宏任务
  • Process.nextTick 优先级高于 Promise.then

在这里插入图片描述

根据上图,结合前面的观点,以下是我的理解:
1、首先,js会把所有的script标签放到宏任务队列里;
2、接着会判断第一个script标签这个宏任务里有没有微任务如果有就先执行微任务,如果碰到宏任务,则把这个宏任务加到宏任务队列里(也就是script标签任务队列的末尾),如果执行完该宏任务里的所有的微任务后,就执行宏任务队列里的下一个宏任务(script标签),以此类推;
3、执行完宏任务队列里所有的script标签后,接着执行从第一个script标签里加入到宏任务队列里的宏任务(后面的执行顺序就与上一步相同,先执行该宏任务里的微任务,将里面的宏任务加到宏任务队列的末尾,当执行完所有的微任务后,执行宏任务队列里的下一个宏任务,以此类推,直到执行完所有的宏任务);
4、如果在执行微任务时遇到宏任务,照样把他加入到宏任务队列里;如果在执行微任务时遇到微任务,则接着执行里面的微任务,直到微任务里没有微任务再执行后面的微任务或下一个宏任务
5、宏任务如果出现在微任务之前,需要先把宏任务放到宏任务队列里,再执行微任务但是还是先执行微任务宏任务在这里的操作只是加入到队列里,并没有执行

<script> 
	console.log("第一个宏任务(script-1)")  
    setTimeout(() => {
        console.log('第三个宏任务')
    })

    Promise.resolve().then(() => {
        console.log('第 1 个微任务');
        setTimeout(() => {
            console.log('第四个宏任务')
        })
    })
</script>
<script>
	console.log("第二个宏任务(script-2)")
    setTimeout(() => {
        console.log('第五个宏任务')
    })

    Promise.resolve().then(() => {
        console.log('第 2 个微任务');
        setTimeout(() => {
            console.log('第六个宏任务')
        })
    })
</script>

在这里插入图片描述

单看代码可能懵懵懂懂,大家可以根据上面我总结的观点进行一步一步的进行:
1、首先,有两个script标签,那就把两个script标签先放到宏任务队列里
2、先看里面有没有微任务,发现里面有一个微任务,就先执行微任务,同时把里面的宏任务按照出现的顺序加入到宏任务队列里
3、第一个script标签里的微任务执行完后,接着执行下一个宏任务,也就是第二个script标签,还是先判断里面有没有微任务,发现有一个微任务,就先执行微任务,同时把里面的宏任务按照出现的顺序加入到宏任务队列里
4、执行完第二个script标签中的微任务后,接着执行下一个宏任务,也就是在第一个script标签中加到宏任务队列里的第一个宏任务(setTimeOut)
5、按照宏任务队列里的顺序执行剩下的宏任务

<script>
	console.log("第一个宏任务(script-1)")  
    setTimeout(() => {
        console.log('第三个宏任务')
    })

    Promise.resolve().then(() => {
        console.log('第 1 个微任务');
        setTimeout(() => {
            console.log('第四个宏任务')
        })
    })

	Promise.resolve().then(() => {
            console.log('第 2 个微任务')
        }).then((res) => {

        console.log('第 3 个微任务')

        setTimeout(() => {
            console.log('第五个宏任务')
        })
    })
</script>
<script>
	console.log("第二个宏任务(script-2)")
    setTimeout(() => {
        console.log('第六个宏任务')
    })

    Promise.resolve().then(() => {
        console.log('第 4 个微任务');
        setTimeout(() => {
            console.log('第七个宏任务')
        })
    })

	Promise.resolve().then(() => {
            console.log('第 5 个微任务')
        }).then((res) => {
        console.log('第 6 个微任务')

        setTimeout(() => {
            console.log('第八个宏任务')
        })
    })
</script>

大家可以按照上述方法判断一下这段代码里宏任务和微任务的执行顺序,我就不带着大家一步一步走了,有问题的话可以私信我
下面是这段代码的执行结果,可以做一下参考

在这里插入图片描述

3、补充

在这里插入图片描述

1、任务队列中的任务都是宏观任务
2、每个宏观任务都有一个自己的微任务队列,执行完所有的微任务后再执行下一个宏任务
3、在执行微任务过程中产生的新的微任务并不会推迟到下个宏任务中执行,而是在当前的宏任务中继续执行。

在这里附上两个我参考的网站地址,大家可以去看一看
1、事件循环 | 前端那些事
2、事件循环 - JavaScript Guidebook

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值