前言
在前端开发中,事件循环(Event Loop) 是一个非常重要的概念。它决定了JavaScript代码的执行顺序,尤其是在处理异步任务时(比如定时器、网络请求、Promise等)。今天,我们就来深入探讨浏览器的事件循环机制,尤其是宏任务(Macro Task)和微任务(Micro Task)的区别与执行顺序。
一、什么是事件循环?
JavaScript是单线程,这意味着它一次只能执行一个任务。为了处理异步操作(比如定时器、网络请求等),浏览器引入了事件循环机制。事件循环的核心思想是:不断地从任务队列中取出任务并执行。
事件循环的工作流程可以简单概括为以下几个步骤:
执行同步代码。
执行微任务队列中的所有任务。
执行一个宏任务。
重复上述过程。
二、宏任务和微任务
1. 宏任务
宏任务是指那些由浏览器发起的任务,通常包括:
setTimeout和setInterval定时器DOM事件(如点击事件)
requestAnimationFrameI/O操作(如文件读取)
setImmediate(Node.js环境)
2. 微任务
微任务是指那些由JavaScript引擎发起的任务,通常包括:
Promise的then和catch回调
MutationObserver(用于监听DOM变化)
process.nextTick(Node.js环境)
3. 执行顺序(非常重要)
事件循环的核心规则是:每次执行一个宏任务后,都会清空微任务队列。
也就是说,微任务的优先级高于宏任务。
三、代码示例与分析
让我们通过几个代码示例来理解事件循环的执行顺序。
示例1:同步代码、宏任务、微任务的执行顺序
console.log('同步代码开始');
setTimeout(() => {
console.log('setTimeout 宏任务');
}, 0);
Promise.resolve().then(() => {
console.log('Promise 微任务');
});
console.log('同步代码结束');
代码执行结果:
同步代码开始
同步代码结束
Promise 微任务
setTimeout 宏任务
分析:
同步代码:首先执行所有的同步代码,输出
同步代码开始和同步代码结束。微任务:然后执行微任务队列中的任务,输出
Promise 微任务。宏任务:最后执行宏任务队列中的任务,输出
setTimeout 宏任务。
示例2:嵌套的宏任务和微任务
console.log('同步代码开始');
setTimeout(() => {
console.log('setTimeout 宏任务1');
Promise.resolve().then(() => {
console.log('Promise 微任务1');
});
}, 0);
setTimeout(() => {
console.log('setTimeout 宏任务2');
Promise.resolve().then(() => {
console.log('Promise 微任务2');
});
}, 0);
console.log('同步代码结束');
输出结果:
同步代码开始
同步代码结束
setTimeout 宏任务1
Promise 微任务1
setTimeout 宏任务2
Promise 微任务2
分析:
同步代码:首先执行所有的同步代码,输出
同步代码开始和同步代码结束。第一个宏任务:执行第一个
setTimeout宏任务,输出setTimeout 宏任务1。第一个微任务:在第一个宏任务执行后,清空微任务队列,输出
Promise 微任务1。第二个宏任务:执行第二个
setTimeout宏任务,输出setTimeout 宏任务2。第二个微任务:在第二个宏任务执行后,清空微任务队列,输出
Promise 微任务2。
示例3:复杂的微任务和宏任务嵌套
console.log('同步代码开始');
Promise.resolve().then(() => {
console.log('Promise 微任务1');
setTimeout(() => {
console.log('setTimeout 宏任务1');
}, 0);
});
setTimeout(() => {
console.log('setTimeout 宏任务2');
Promise.resolve().then(() => {
console.log('Promise 微任务2');
});
}, 0);
console.log('同步代码结束');
输出结果:
同步代码开始
同步代码结束
Promise 微任务1
setTimeout 宏任务2
Promise 微任务2
setTimeout 宏任务1
分析:
同步代码:首先执行所有的同步代码,输出
同步代码开始和同步代码结束。微任务:然后执行微任务队列中的任务,输出
Promise 微任务1,并在微任务中注册了一个新的宏任务setTimeout 宏任务1。第一个宏任务:执行第一个
setTimeout宏任务,输出setTimeout 宏任务2。第二个微任务:在第一个宏任务执行后,清空微任务队列,输出
Promise 微任务2。第二个宏任务:最后执行在微任务中注册的
setTimeout 宏任务1,输出setTimeout 宏任务1。
四、总结
事件循环:JavaScript通过事件循环机制处理异步任务,确保代码的执行顺序。
宏任务:由浏览器发起的任务,如
setTimeout、setInterval等。微任务:由JavaScript引擎发起的任务,如
Promise的then回调。执行顺序:每次执行一个宏任务后,都会清空微任务队列。微任务的优先级高于宏任务。
理解事件循环、宏任务和微任务的执行顺序,对于编写高效的异步代码非常重要。

5121






