Khám Phá Vòng Lặp Sự Kiện (Event Loop) Trong JavaScript
Vòng lặp sự kiện là một trong những khái niệm quan trọng và thú vị nhất trong JavaScript, nhưng lại thường bị hiểu sai. Bài viết này sẽ giúp bạn nắm bắt được cơ chế hoạt động của vòng lặp sự kiện thông qua các ví dụ dễ hiểu, để bạn có thể áp dụng vào thực tế.
Vòng Lặp Sự Kiện Là Gì?
Bạn đã bao giờ thắc mắc làm thế nào JavaScript có thể xử lý nhiều tác vụ một cách hiệu quả mà chỉ có một luồng? Hãy cùng khám phá “ma thuật” của vòng lặp sự kiện trong JavaScript. Vòng lặp sự kiện hoạt động như một người quản lý tại một bữa tiệc, đảm bảo rằng mọi tác vụ đều được tiếp nhận và xử lý theo đúng thứ tự. Mặc dù JavaScript là ngôn ngữ đơn luồng, nó vẫn có khả năng tạo ra ảo giác về đa nhiệm nhờ vào vòng lặp sự kiện.
Cơ Chế Hoạt Động Của Vòng Lặp Sự Kiện
1. Mã Đồng Bộ
javascript
console.log("1️⃣ Bắt đầu nấu ăn 🍳");
console.log("2️⃣ Ăn sáng 🍴");
console.log("3️⃣ Rửa chén 🧼");
Kết quả:
1️⃣ Bắt đầu nấu ăn 🍳
2️⃣ Ăn sáng 🍴
3️⃣ Rửa chén 🧼
Giải thích:
Các tác vụ này được thực hiện một cách tuần tự (đồng bộ).
2. Tác Vụ Không Đồng Bộ Với setTimeout
javascript
console.log("1️⃣ Bắt đầu nấu ăn 🍳");
setTimeout(() => {
console.log("2️⃣ Ăn sáng 🍴 (sau 3 giây)");
}, 3000);
console.log("3️⃣ Rửa chén 🧼");
Kết quả:
1️⃣ Bắt đầu nấu ăn 🍳
3️⃣ Rửa chén 🧼
2️⃣ Ăn sáng 🍴 (sau 3 giây)
Giải thích:
- Nhiệm vụ
setTimeout
sẽ được gửi đến Web API và không làm gián đoạn luồng chính. - Khi thời gian kết thúc, nó sẽ được chuyển vào hàng đợi để chờ luồng chính rảnh rỗi.
- Vòng lặp sự kiện sẽ thực thi các nhiệm vụ đã được đưa vào hàng đợi sau khi xử lý xong các tác vụ đồng bộ.
3. Ưu Tiên Tác Vụ Nhỏ So Với Tác Vụ Lớn
javascript
console.log("1️⃣ Bắt đầu 🍳");
setTimeout(() => {
console.log("2️⃣ Macrotask: Thời gian chờ ⏳");
}, 0);
Promise.resolve().then(() => {
console.log("3️⃣ Microtask: Lời hứa ✅");
});
console.log("4️⃣ Kết thúc 🚀");
Kết quả:
1️⃣ Bắt đầu 🍳
4️⃣ Kết thúc 🚀
3️⃣ Microtask: Lời hứa ✅
2️⃣ Macrotask: Thời gian chờ ⏳
Giải thích:
Lệnh gọi lại từ Promise
(microtask) sẽ được thực thi trước lệnh gọi lại từ setTimeout
(macrotask), ngay cả khi độ trễ là 0ms.
4. Xử Lý Tác Vụ Nặng
Bạn đã bao giờ gặp tình trạng trang web bị đông cứng khi thực hiện tác vụ nặng chưa? Dưới đây là một ví dụ về mã không tối ưu:
javascript
console.log("1️⃣ Bắt đầu 🏁");
for (let i = 0; i < 1e9; i++) {} // Giả lập tác vụ nặng
console.log("2️⃣ Kết thúc 🛑");
Và đây là cách tối ưu bằng cách sử dụng setTimeout
cho chunking:
javascript
console.log("1️⃣ Bắt đầu 🏁");
let count = 0;
function heavyTask() {
if (count < 1e6) {
count++;
if (count % 100000 === 0) console.log(`Đã xử lý ${count} mục 🔄`);
setTimeout(heavyTask, 0); // Để vòng lặp sự kiện thở!
} else {
console.log("2️⃣ Tác vụ hoàn thành ✅");
}
}
heavyTask();
Tóm Tắt
1️⃣ JavaScript thực hiện mã đồng bộ trước khi xử lý bất kỳ tác vụ không đồng bộ nào.
2️⃣ Vòng lặp sự kiện sẽ quản lý và thực hiện các tác vụ không đồng bộ (như setTimeout
).
3️⃣ Các tác vụ nhỏ (microtasks) sẽ được ưu tiên hơn các tác vụ lớn (macrotasks).
4️⃣ Chia nhỏ các tác vụ nặng ra thành các phần nhỏ để giữ cho giao diện người dùng luôn phản hồi tốt.
source: viblo