Event Loop là gì?
Event Loop là cơ chế cho phép JavaScript thực thi mã bất đồng bộ trong một môi trường đơn luồng. Nó vận hành bằng cách liên tục kiểm tra hàng đợi microtask và hàng đợi macrotask, nơi lưu trữ các callback của các hoạt động đang chờ thực thi.
Microtask và macrotask là gì?
- Microtask: Là các tác vụ nhỏ, cần thực thi ngay sau khi mã đồng bộ hoàn tất. Ví dụ: Promises, queueMicrotask.
- Macrotask: Là các tác vụ ít khẩn cấp hơn, thực thi sau khi tất cả các microtask đã hoàn tất. Ví dụ: setTimeout, setInterval, và các sự kiện giao diện người dùng (UI Events).
Sự khác biệt chính giữa microtask và macrotask
- Mức độ ưu tiên: Vòng lặp sự kiện luôn ưu tiên microtask trước. Khi tất cả microtask được xử lý xong, JavaScript mới chuyển sang xử lý macrotask.
- Thời điểm thực thi: Microtask được thực thi ngay sau khi mã đồng bộ kết thúc, trong khi macrotask chờ đến lượt sau cùng.
Đặc điểm | Microtask | Macrotask |
---|---|---|
Ưu tiên | Cao | Thấp |
Ví dụ | Promises, queueMicrotask | setTimeout , setInterval |
Thời điểm thực thi | Ngay sau mã đồng bộ | Sau khi microtask hoàn tất |
Ví dụ minh hoạ
Dự đoán kết quả:
- Nhiều người sẽ nghĩ kết quả là:
Start -> Timeout -> Promise -> End
. - Nhưng thực tế, kết quả là:
Start -> End -> Promise -> Timeout
.
Phân tích:
- Mã đồng bộ (
console.log("Start"
,"End"
) được thực thi trước. - Callback của
Promise.resolve
được đặt trong hàng đợi microtask và thực thi ngay sau mã đồng bộ. - Callback của
setTimeout
được đặt trong hàng đợi macrotask và chỉ thực thi sau khi microtask đã hoàn tất.
Sau khi tất cả các tác vụ đồng bộ đã thực thi, Event Loop sẽ quét Microtask Queue trước, và thực hiện then() để in ra “Promise”.
Cuối cùng, khi hàng đợi microtask đã trống, macrotask setTimeout sẽ được thực hiện và in ra “Timeout”.
Event Loop: Code đồng bộ > MicroTask > MacroTask
Tại sao cần hiểu rõ sự khác biệt?
Hiểu rõ microtask và macrotask giúp:
- Tối ưu hóa hiệu suất: Hạn chế việc tạo quá nhiều microtask, tránh làm chậm event loop.
- Tránh lỗi logic: Biết thứ tự thực thi để kiểm soát tốt hơn luồng xử lý mã.
Cách tối ưu hóa code JavaScript
- Ưu tiên sử dụng Promise hoặc async/await: Việc này giúp mã dễ đọc hơn, tránh callback lồng nhau.
- Sử dụng queueMicrotask: Khi muốn lên lịch một tác vụ ngay sau mã đồng bộ, đây là phương pháp hiệu quả và đáng tin cậy hơn
setTimeout(0)
.
Kết luận
Hiểu rõ cơ chế hoạt động của microtask và macrotask là yếu tố quan trọng để tối ưu mã JavaScript. Từ đó, bạn có thể tránh được các lỗi logic và cải thiện hiệu suất của ứng dụng.
Tham khảo: