Mở đầu
- JavaScript là một ngữ lập trình
chạy đơn luồng - single-threaded
!!! Nếu vậy không phải một tác vụ chạy quá lâu thì sẽ ngăn chặn các tác vụ phía sau gây nên tình trạng trang web bị treo! 🤔
- Nhưng thực chất khi truy cập, tương tác với các website trên trình duyệt chúng ta vẫn thấy mọi thứ được xử lý rất mượt mà!
- Vậy phải có một cơ chế độc đáo để quản lý các tác vụ này mà không gây tắc nghẽn hệ thống?!
- Đó chính là lúc
Event Loop
xuất hiện và làm chủ cuộc chơi 😎.
Event Loop là gì?
Event Loop
là một thành phần của Javascript Runtime Environment (môi trường thực thi Javascript)
.
Event Loop
giúp quản lý, thực thi các tác vụ một cách bất đồng bộ mà không lo việc phải chờ đợi lẫn nhau.
- Chúng ta hãy cùng tìm hiểu chi tiết hơn về
Javascript Runtime Environment
, cách thức hoạt động và vai trò của Event Loop
trong hệ thống này như thế nào nhé !
JavaScript Runtime Environment
JavaScript Runtime Environment
là nơi để xử lý và thực thi các tác vụ liên quan đến JavaScript
.
- Để
JavaScript
có thể thực thi một cách mượt mà thì cần đến các thành phần chính sau:
![]() |
Sơ đồ mô tả luồng thực thi Javascript và các thành phần của Javascript Runtime Enviroment |
1. JavaScript Engine
- Tất nhiên điều quan trọng tiên quyết là chúng ta phải có một trình biên dịch để dịch mã
JavaScript
thành mã nhị phân để máy tính có thể hiểu và thực thi.
- Bạn có thể tìm hiểu chi tiết hơn trong bài viết sau để hiểu rõ hơn về cấu tạo của
JavaScript Engine
: V8 Engine trong Chrome và Node.js
- Nhưng
JavaScript Engine
chỉ có thể xử lý được các đoạn mã thuần và chạy một cách đồng bộ (chạy theo nguyên lý hàng đợi Stack).
js
// Javascript Engine chỉ có thể xử lý các đoạn mã Javascript thuần như:
// ghi log
console.log("Learning Javascript");
// khai báo biến
const a = 1
- Để có thể xử lý được các đoạn mã phức tạp hơn như:
kết nối đến giao thức Http, quản lý các tác vụ bất đồng bộ, các sự kiện để tác động đến DOM, CSDOM tree,...
thì lúc này chúng ta cần sự hỗ trợ thêm của các thành phần khác.
2. Web / Browser Api
Web / Browser Api
là các API cung cấp bởi Runtime Environment (Browser, Node.Js)
.
API (Application Programming Interface)
chính là công cụ để Javascript
có thể giao tiếp được với môi trường bên ngoài !
2.1. DOM
DOM (Document Object Model)
là một tập hợp các phương thức giúp JavaScript
giao tiếp, tương tác với HTML/CSS
.
- Các phương thức này được
thực thi một cách đồng bộ (synchoronous)
.
js
// Tạo nội dụng HTML cho phần tử với id="mydiv"
document.getElementById("mydiv").innerHTML = "Hello Viblo!!!";
// Đổi màu chữ thành màu xanh dương cho phần tử với id="mydiv"
document.getElementById("mydiv").style.color = "blue";
2.2. Web Storage Api
Web Storage API
giúp lưu trữ dữ liệu trên trình duyệt của người dùng theo hai dạng chính:
Loại |
Chức năng |
localStorage |
Lưu dữ liệu vĩnh viễn, không bị mất khi đóng trình duyệt. |
sessionStorage |
Lưu dữ liệu tạm thời, bị mất khi đóng tab trình duyệt. |
js
// localStorage
localStorage.setItem("username", "ThanhEtn");
localStorage.getItem("username");
// sessionStorage
sessionStorage.setItem("token", "abc123");
sessionStorage.getItem("token");
2.3. Web Worker Api
Web Worker
giúp xử lý công việc nặng trên background thread
(một thread riêng biệt chạy trong nền), giữ cho main thread (UI)
không bị chặn.
- Một số tác vụ mà
Web Worker
có thể xử lý một cách hiệu quả:
Tác vụ |
Mô tả |
Xử lý tính toán phức tạp |
Xử lý dữ liệu lớn, tính toán số nguyên tố |
Xử lý dữ liệu lớn |
Parse file JSON lớn, xử lý dữ liệu log, thống kê số liệu |
Gọi API & Xử lý dữ liệu |
Fetch, WebSockets, IndexedDB, Timer API |
Nén & Giải nén dữ liệu |
Nén ảnh, video, file trước khi gửi đi |
js
// Gửi yêu cầu Https đến server
async function getData () {
const response = await fetch("https://viblo.asia/api/posts/newest?limit=20");
return await response.json();
}
// SetTimeOut - Timer API
console.log("Chạy trong Main Thread");
setTimeout(() => {
console.log("Đã chờ 3 giây trong Web Worker!");
}, 3000);
- Vậy khi các tác vụ này đã được thực thi xong trong
Web Worker
thì thành phần nào sẽ đưa chúng trở lại Call Stack
để thực thi 🤔?
3. Task Queue / MicroTask Queue
Các tác vụ bất đồng bộ (asynchoronous)
sau khi đã thực thi xong trong Web Worker
sẽ được đưa vào các hàng đợi đặt biệt là: Task Queue, MicroTask Queue
.
- Các hàng đợi (Queue) này được thực thi theo quy tắc:
FIFO (First In, First Out)
. Tức là tác vụ nào được đưa vào hàng đợi trước sẽ được thực thi trước.
js
// Task 1 vào hàng đợi trước Task 2, nên nó sẽ được thực thi trước
setTimeout(() => console.log("Task 1"), 0);
setTimeout(() => console.log("Task 2"), 0);
MicroTask Queue
có thứ tự ưu tiên cao hơn so với Task Queue
. Các tác vụ trong MicroTask Queue
sẽ được thi đến khi nào rỗng thì mới tới các tác vụ trong Task Queue
được thực thi.
js
console.log("Start");
setTimeout(() => console.log("Task Queue"), 0);
Promise.resolve().then(() => console.log("MicroTask Queue"));
console.log("End");
Trình tự thực thi |
1. "Start" → Call Stack (thực thi ngay) |
2. setTimeout() → Gửi vào Task Queue |
3. Promise.then() → Gửi vào MicroTask Queue |
4. "End" → Call Stack (thực thi ngay) |
5. MicroTask Queue chạy trước → "MicroTask Queue" |
6. Sau khi MicroTask Queue trống → "Task Queue" được thực thi. |
- Nhưng
CallStack
có phải lúc nào cũng trong trạng thái sẵn sàng để các tác vụ trong Queue
có thể được đưa vào thực thi?
4. Event Loop
Event Loop
chính là chiếc cầu nối giữa Call Stack
với Task Queue, MicroTask Queue
. Giúp đảm bảo các tác vụ bất đồng bộ xử lý một cách mượt mà dù Javascript
chỉ chạy 1 luồng duy nhất 😎💯.
- Các nhiệm vụ chính mà
Event Loop
thực hiện đó là:
- Kiểm tra trạng thái của
Call Stack
nếu trống sẽ tìm một tác vụ mới từ Queue
để đẩy vào Call Stack
thực thi.
- Ưu tiên lấy tác vụ từ
MicroTask Queue
trước. Xử lý từng tác vụ trong đây và đưa vào Call Stack
để thực thi.
- Khi
MicroTask Queue
đã rỗng. Lấy từng tác vụ trong Task Queue
đưa vào Call Stack
để thực thi.
![]() |
Sơ đồ mô tả cách Event Loop hoạt động |
Kết luận
Javascript
một ngôn ngữ chạy đơn luồng nhưng với một kiến trúc tuyệt vời của Javascript Runtime Enviroment
đã có thể xử lý một cách mượt mà các tác vụ, tạo ra một trải nghiệm tuyệt vời cho người dùng.
- Nhờ vào sự kết hợp vô cùng ăn ý giữa các thành phần. Đặc biệt trong đó là
Event Loop
giúp điều phối sự hoạt động của các tác vụ đồng bộ và bất đồng bộ với nhau.
- Hy vọng qua bài viết, giúp các bạn có một cái nhìn chi tiết về cách thức
Javascript
được thực thi cũng như giải đáp được thắc mắc ở đầu bài viết về ngôn ngữ đơn luồng lại có thể xử lý được các tác vụ bất đồng bộ 🤩.