接下来我会详细讲解一下JS事件循环机制(event loop)、宏任务和微任务的原理,以及该如何理解它们之间的关系。
1. 事件循环机制(event loop)的原理
在JavaScript中,事件循环机制定义了一种代码执行模型,可以控制代码在何时执行。事件循环机制主要分为以下两个部分:
- 执行栈(Execution Context Stack)
- 任务队列(Task Queue)
我们可以将代码执行栈看做是一个存储函数执行上下文的地方,每当调用一个函数,就会将其对应的执行上下文压入栈中,并等待执行完毕。而任务队列则存储了当前已经准备好的任务,它们会在其他任务执行完成后,由事件循环机制取出来执行。
当JavaScript引擎首次遇到全局代码时,它会创建一个全局执行上下文,并将它压入执行栈中。而后续的任何JavaScript代码执行,都会通过执行栈中不断地加入和弹出执行上下文来实现。
在事件循环机制中,除了主线程(执行栈)之外,还有一个任务队列(Task Queue)。任务队列会接受异步任务并按照顺序存储起来,这些异步任务又分为两种类型:宏任务和微任务。
2. 宏任务和微任务的原理
宏任务
宏任务指的是那些需要进入事件队列与其他事件竞争执行权的代码块,例如:load事件、定时器事件(setTimeout、setInterval)等。
当执行栈为空时,事件循环机制会从宏任务队列中取出任务来执行,执行时期间可能会导致执行栈中再次压入执行上下文,也可能会影响变量的状态。当执行过程完成后,事件循环机制会在检查当前宏任务队列和微任务队列是否为空的情况下,执行位于队列头部的任务。
示例:
console.log('1');
setTimeout(() => {
console.log('2');
}, 0);
console.log('3');
执行结果:
1
3
2
很显然,setTimeout函数会被放入宏任务队列中,而由于发生了异步调用,因此不会阻止主线程的执行。最后,任务队列中的宏任务被执行,并打印出“2”
微任务
微任务指的是在JavaScript引擎执行栈为空并且调用栈中的所有函数都已经返回的情况下,需要执行的代码块,例如Promise回调函数、MutationObserver监听等。
当执行栈为空时,事件循环机制会优先处理微任务队列中的任务,如果没有微任务需要处理,则会切换到宏任务队列中的事件。
示例:
console.log(1);
setTimeout(() => {
console.log(2);
});
new Promise(resolve => {
console.log(3);
resolve(4);
}).then((value) => {
console.log(value);
});
console.log(5);
执行结果:
1
3
5
4
2
在以上的示例中,Promise回调函数会被放入微任务队列中,而由于异步调用发生在“35”行代码之后,因此在主线程执行完之前,Promise回调函数就已经被放入了微任务队列中,事件循环机制就会在执行完成主线程中的执行栈之后,优先执行Promise回调函数这个微任务。最终,任务队列中的宏任务被执行,并打印出“2”。
结语
以上就是JS事件循环机制和宏任务微任务的完整攻略。通过对比分析,我们可以得出一条结论:无论是宏任务还是微任务,事件循环机制都会按照队列中的顺序依次执行它们。根据实际的业务场景,可以将需要执行的代码加入到微任务或宏任务队列中,帮助JavaScript引擎更好地控制代码的执行时机。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JS事件循环机制event loop宏任务微任务原理解析 - Python技术站