从一道题目窥探事件循环机制
2024-01-07 13:17:45
从一道题目窥探事件循环机制
在学习JavaScript的过程中,我们经常会听到“事件循环”这个概念。它是一个非常重要的机制,决定了JavaScript代码的执行顺序。为了更好地理解事件循环,我们先来看一道题目:
在浏览器控制台依次输入以下代码,请写出代码的输出顺序:
console.log('1'); // 同步任务
setTimeout(() => {
console.log('2'); // 宏任务
}, 0);
Promise.resolve().then(() => {
console.log('3'); // 微任务
});
这道题目看似简单,但它却涵盖了事件循环机制的几个关键概念:执行栈、消息队列、事件队列、宏任务和微任务。
执行栈
执行栈是一个后进先出的栈,用于记录当前正在执行的函数。当一个函数被调用时,它会将该函数push到执行栈顶,当该函数执行完成后,它将栈顶函数pop弹出。
消息队列
消息队列是一个先进先出的队列,用于存储那些需要异步执行的任务,比如setTimeout的回调函数、Promise的then方法等。当执行栈为空时,系统会从消息队列中取出一个任务执行。
事件队列
事件队列是一个先进先出的队列,用于存储那些需要在页面上触发的事件,比如点击事件、鼠标移动事件等。当执行栈为空时,系统会从事件队列中取出一个事件执行。
宏任务
宏任务是指那些需要较长时间才能完成的任务,比如setTimeout的回调函数、setInterval的回调函数等。宏任务会先被放入消息队列中,当执行栈为空时,系统会从消息队列中取出一个宏任务执行。
微任务
微任务是指那些需要立即执行的任务,比如Promise的then方法、MutationObserver的回调函数等。微任务会先被放入消息队列中,当执行栈为空时,系统会从消息队列中取出所有微任务执行,然后再取出宏任务执行。
代码输出顺序
现在我们来分析一下这道题目的代码输出顺序:
- console.log('1'); // 同步任务
- Promise.resolve().then(() => {
console.log('3'); // 微任务
}); - setTimeout(() => {
console.log('2'); // 宏任务
}, 0);
首先,console.log('1')是一个同步任务,它会立即执行并输出“1”。
然后,Promise.resolve().then(() => {
console.log('3'); // 微任务
});是一个微任务,它会先被放入消息队列中。
最后,setTimeout(() => {
console.log('2'); // 宏任务
}, 0);是一个宏任务,它也会先被放入消息队列中。
当执行栈为空时,系统会先从消息队列中取出微任务执行,因此console.log('3')会输出“3”。
然后,系统会从消息队列中取出宏任务执行,因此setTimeout的回调函数会输出“2”。
所以,这道题目的代码输出顺序是:“1”、“3”、“2”。
总结
通过这道题目,我们对JavaScript中的事件循环机制有了一个基本的了解。事件循环机制是一个非常重要的概念,它决定了JavaScript代码的执行顺序。在实际开发中,我们经常会遇到与事件循环机制相关的问题,因此掌握事件循环机制的知识非常重要。