事件循环| 宏任务和微任务代码的执行顺序

首先先看代码:

async function async1() {
    console.log(1);
    await async2();
    console.log(2);
}
async function async2() {
    console.log(3);
}
console.log(4);
setTimeout(function () {
console.log(5);
}, 0);
async1();
new Promise(function (resolve) {
console.log(6);
resolve();
}).then(function () {
console.log(7);
});
console.log(8);
//输出
4 1 3 6 8 2 7 5

原因分析:

1.JS单线程

我们都知道JS是单线程语言,即单个程序只能创建一个执行的线程来完成任务。

为什么JavaScript是单线程?
其实javascript的单线程特点是跟他的用途有关的。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。假如不是单线程的话,在一个线程当我们在给某个DOM节点增加内容的时候,另一个线程正在删除这个DOM节点的内容,那还得了,那不是乱套了吗。所以javascript只能是单线程。

2.同步异步、事件循环

由于JS单线程的特点,js中的任务按顺序一个一个的执行,但当我们遇到需要较长时间才能返回执行结果的任务时,后面的任务就需要等待,带来较高的性能消耗。为了解决这种情况,将任务分为了同步任务和异步任务,并引入了JS事件循环(即EventLoop)机制,来执行异步任务。

同步: 能立即得到结果的任务称为同步任务,多个同步任务在主线程上排队依次执行,前一个任务执行完才能执行下一个任务。即程序执行顺序与任务的排队顺序是一致的、同步的;

异步: 需要一段时间之后才能得到结果的任务称为异步任务,异步任务不进入主线程,而是进入任务队列中,这样遇到异步任务时就不用在主线程等其执行完再执行下一个任务,而是跳过异步任务,继续在主线程执行下一个同步任务。此时程序的执行顺序和任务的排列顺序是不一致的、异步的。

事件循环机制
img

整体原则:先同步再异步,先执行宏任务再执行微任务,在执行任何的宏任务之前都需要先保证清空微任务队列

  • 当任务进入执行栈,首先判断任务是同步还是异步,同步和异步任务分别进入不同的执行"场所",同步任务进入主线程直接执行,异步的进入Event Table并注册函数。
  • 当指定的事情完成时,Event Table会将这个函数移入Event Queue。
  • 当主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行。
  • 主线程从“任务队列”中读取执行事件,这个过程是循环不断的,也就是常说的Event Loop(事件循环)机制

3.宏任务、微任务

事件循环机制具体流程:
异步任务可分为宏任务、微任务。当同步任务执行完,先去事件队列查找执行一个宏任务,然后检查microtask队列是否为空,如果不为空则一次性执行所有微任务,微任务执行完继续去执行主线程任务,开启下一次事件循环。
img

宏任务<script>整体代码、setTimeout、setInterval、ajax、DOM事件

浏览器Node
<script>整体代码
setTimeout
setInterval
setImmediatex
requestAnimationFramex
Ajax
DOM事件

微任务:promise.then catch finally (await)

#浏览器Node
process.nextTickx
MutationObserverx
Promise.then catch finally

4.题目解析

//1. 整段代码作为宏任务进入执行
async function async1() {
    console.log(1);//5. 输出1
    await async2();//6. 运行async2
    console.log(2);//8. 放入微任务队列
}
async function async2() {
    console.log(3);//7. 输出3 
}
console.log(4);//2. 同步代码直接执行,输出4
setTimeout(function () {
console.log(5);//3. 放到宏任务队列
}, 0);
async1();// 4. 运行async1
new Promise(function (resolve) {
console.log(6);//9. 同步代码,输出6
resolve();
}).then(function () {
console.log(7);//10、 放入微任务队列
});
console.log(8);//11、 输出8

在这里插入图片描述
简单来说,执行一段代码时,整段代码会作为宏任务进入主线程执行,接下来会有3种情况:

同步代码,直接执行
碰到setTimeout,分发到宏任务队列
碰到Promise.then,分发到微任务队列

参考资料:宏任务和微任务代码的执行顺序 - 腾讯云开发者社区-腾讯云 (tencent.com)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
JS的循环机制是指如何处理事件循环中的任务。在JS中,事件循环是一种机制,用于处理异步操作和事件处理。循环机制确保任务按照正确的顺序执行,以保证代码的正确性和性能。 在循环机制中,有两种类型的任务:宏任务(macro-task)和微任务(micro-task)。宏任务包括整体代码块、setTimeout、setInterval等,而微任务包括Promise、MutationObserver、process.nextTick等。 当代码执行时,会首执行当前代码块中的同步任务,然后执行微任务队列中的所有微任务。接下来,会从宏任务队列中选择一个任务执行,直到宏任务队列为空。然后,再次执行所有微任务,以此类推。 事件队列是用来存储待执行的任务的数据结构。每个宏任务微任务都会被添加到事件队列中。当事件循环开始时,会从事件队列中依次取出任务并执行。 需要注意的是,微任务的优级高于宏任务。也就是说,在执行完当前宏任务后,会立即执行所有微任务,然后再执行下一个宏任务。这样可以确保微任务能够尽早地被执行,避免出现不必要的延迟。 总结一下: - 循环机制确保异步任务按照正确的顺序执行。 - 宏任务包括整体代码块、setTimeout、setInterval等。 - 微任务包括Promise、MutationObserver、process.nextTick等。 - 事件队列用来存储待执行的任务。 - 微任务级高于宏任务

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值