JavaScript 事件循环
总结图解(简单版)
同步代码 → 微任务队列 → 宏任务队列 → UI 渲染
↑ ↑
└─> 事件循环 ─┘
- 同步代码执行完后,先执行微任务。
- 然后从宏任务队列中取出一个任务执行。
- 在每次执行完宏任务后,都会检查并执行微任务,直到微任务队列为空。
- 如果有必要,进行 UI 渲染
执行顺序:JavaScript 是单线程的,执行顺序分成同步任务和异步任务。 调用栈:同步任务会直接按顺序进入调用栈执行。 任务队列:异步任务会进入任务队列,分为微任务队列和宏任务队列。 微任务:优先级高,如 Promise.then、queueMicrotask。 宏任务:优先级低,如 setTimeout、setInterval、I/O 操作、UI 渲染、事件触发(如用户输入、点击等) 事件循环:每次调用栈清空后,事件循环会先执行所有微任务,再执行一个宏任务,循环往复
其他
JavaScript 是单线程执行的,意味着同一时刻只能执行一个任务。为了有效处理异步操作和避免阻塞主线程,JavaScript 引入了事件循环(Event Loop)机制,它协调了同步任务、异步任务以及 UI 渲染等操作。
基本流程
- 同步代码执行:
代码从上到下一行一行执行,遇到同步任务时,直接压入调用栈(Call Stack)并执行。
- 异步代码处理:
当遇到异步任务时(如 setTimeout、Promise 等),这些任务不会立刻执行,而是会被放入对应的队列中(宏任务队列或微任务队列)。
- 事件循环执行流程:
1.同步代码先执行完。
2.微任务队列中的任务优先执行,直到队列为空。
3.然后,宏任务队列中的任务依次执行。
4.在每次执行完一个宏任务后,都会检查微任务队列,执行所有微任务。
- UI 渲染:
每次执行完宏任务后,浏览器会进行 UI 渲染,但只有在宏任务执行完、微任务队列为空时才会进行渲染
一般会考,代码运行结果是啥
案例 01
setTimeout(() => {
console.log(1);
}, 0);
const promise = new Promise((resolve, reject) => {
console.log(2);
reject(3); // 不会中断执行,还是会执行下面的4,除非 return reject(3)
console.log(4);
});
promise
.then(() => console.log(5))
.catch(() => console.log(6)) // catch返回一个新的promise,并且 catch 中没有再抛错,所以返回的promise状态变成fulfilled,会被后面的then成功回调执行
.then(() => console.log(7))
.catch(() => console.log(8)) // 前面的catch和then都没有抛错,所以不会执行
.then(() => console.log(9));
console.log(10);
// 2, 4, 10 (同步任务), 5, 7, 9,(微任务) 1(宏任务)
案例 02
function test() {
console.log(1);
setTimeout(function () {
// timer1
console.log(2);
}, 1000);
}
test();
setTimeout(function () {
// timer2
console.log(3);
});
new Promise(function (resolve) {
console.log(4);
setTimeout(function () {
// timer3
console.log(5);
}, 100);
resolve();
}).then(function () {
setTimeout(function () {
// timer4
console.log(6);
}, 0);
console.log(7);
});
console.log(8);
// 1, 4, 8 (同步任务), 7(微任务),
// 3(宏任务,它的时间虽然是0,但是它在最前面,js 是从上往下一行一行执行), 6(宏任务), 5(宏任务), 2(宏任务)
案例 03
async function async1() {
console.log(1);
await async2();
console.log(2);
}
async function async2() {
console.log(3);
}
console.log(4);
setTimeout(() => {
console.log(5);
}, 0);
async1();
new Promise((resolve, reject) => {
console.log(6);
resolve();
}).then(() => {
console.log(7);
});
console.log(8);
// 4, 1, 3, 6, 8(同步任务), 2(微任务), 7(微任务), 5(宏任务)
上面里面一部分代码
async function async1() {
console.log(1);
await async2();
console.log(2);
}
等价于;
async function async1() {
console.log(1);
async2().then(() => {
console.log(2);
});
}
案例 05
setTimeout(() => {
console.log("A");
Promise.resolve().then(() => {
console.log("B");
});
}, 1000);
Promise.resolve().then(() => {
console.log("C");
});
new Promise((resolve) => {
console.log("D");
resolve("");
}).then(() => {
console.log("E");
});
async function sum(a, b) {
console.log("F");
}
async function asyncSum(a, b) {
await Promise.resolve();
console.log("G");
return Promise.resolve(a + b);
}
sum(3, 4);
asyncSum(3, 4);
// D, F, C, E, G, A, B
案例 06
console.log("script start"); // 1
setTimeout(function () {
console.log("setTimeout"); // 5
}, 0);
new Promise((res, rej) => {
console.log("promise"); // 2
rej(); // 这里拒绝了啊
})
.then(function () {
console.log("promise1");
})
.catch(function () {
return 1;
})
.then(function () {
console.log("promise2"); // 4
});
console.log("script end"); // 3