Giới thiệu về lập trình bất đồng bộ trong JavaScript
Trong JavaScript, lập trình bất đồng bộ (Asynchronous Programming) là một khái niệm quan trọng giúp xử lý các tác vụ mất thời gian mà không làm gián đoạn toàn bộ chương trình. Bài học này sẽ giúp bạn hiểu sự khác biệt giữa lập trình đồng bộ (synchronous) và bất đồng bộ (asynchronous), cách Vòng lặp sự kiện (Event Loop) hoạt động, và một số ví dụ thực tế về các tác vụ bất đồng bộ.

Asynchronous Programming
1. Bất đồng bộ là gì? So sánh Đồng bộ vs Bất đồng bộ
Đồng bộ (Synchronous):
- Code được thực thi tuần tự từ trên xuống dưới.
- Mỗi dòng code phải hoàn thành trước khi dòng tiếp theo chạy.
- Nếu một đoạn code mất nhiều thời gian (ví dụ: đọc file, gọi API), chương trình sẽ bị chặn (blocking).
Ví dụ về lập trình đồng bộ:
console.log("Bắt đầu");
for (let i = 0; i < 1000000000; i++) {} // Mô phỏng một tác vụ nặng
console.log("Kết thúc");
Kết quả:
- "Bắt đầu"
- (Đợi lâu...)
- "Kết thúc"
Bất đồng bộ (Asynchronous):
- Cho phép chương trình tiếp tục thực thi mà không cần chờ các tác vụ khác hoàn thành.
- Giúp JavaScript hoạt động hiệu quả hơn khi xử lý các tác vụ như gọi API, đọc file, hoặc setTimeout.
- Sử dụng Callback, Promises, Async/Await để quản lý luồng bất đồng bộ.
Ví dụ về lập trình bất đồng bộ:
console.log("Bắt đầu");
setTimeout(() => {
console.log("Đã hoàn thành tác vụ mất thời gian!");
}, 2000);
console.log("Kết thúc");
Kết quả:
- "Bắt đầu"
- "Kết thúc"
- (Sau 2 giây) "Đã hoàn thành tác vụ mất thời gian!"
Kết luận: Lập trình bất đồng bộ giúp JavaScript có thể tiếp tục chạy mà không bị chặn bởi các tác vụ mất thời gian.
2. Vòng lặp sự kiện (Event Loop) trong JavaScript
JavaScript là một ngôn ngữ đơn luồng (Single-threaded), nhưng nhờ cơ chế Event Loop, nó có thể xử lý nhiều tác vụ bất đồng bộ mà không bị chặn.
Event Loop hoạt động như thế nào?
- Call Stack (Ngăn xếp lời gọi): Chạy từng hàm theo thứ tự.
-
Web API (Hệ thống xử lý tác vụ nền): Quản lý các tác vụ bất đồng bộ như
setTimeout
, HTTP request. - Callback Queue (Hàng đợi xử lý): Lưu các hàm cần chạy khi một tác vụ bất đồng bộ hoàn thành.
- Event Loop: Kiểm tra nếu Call Stack rảnh, nó sẽ lấy các hàm từ Callback Queue để chạy.
Ví dụ minh họa Event Loop:
console.log("1");
setTimeout(() => {
console.log("2");
}, 0);
console.log("3");
Kết quả in ra:
- "1"
- "3"
- "2" (Dù setTimeout là 0ms, nó vẫn chạy sau các tác vụ đồng bộ khác)
Bài học rút ra:
- Các tác vụ đồng bộ luôn được thực thi trước.
- Các tác vụ bất đồng bộ sẽ đợi trong hàng đợi và chỉ chạy khi Call Stack rảnh.
3. Ví dụ về các tác vụ bất đồng bộ trong thực tế
-
HTTP Request (Gọi API)
- Khi lấy dữ liệu từ server, trình duyệt sẽ không chờ mà tiếp tục chạy các đoạn code khác.
fetch("https://jsonplaceholder.typicode.com/todos/1")
.then(response => response.json())
.then(data => console.log("Dữ liệu từ API:", data));
console.log("Chương trình không bị chặn!");
Kết quả:
- "Chương trình không bị chặn!" in ra trước.
- Dữ liệu từ API chỉ hiển thị sau khi tải xong.
- setTimeout() – Trì hoãn một tác vụ
- Dùng để thực thi một đoạn code sau một khoảng thời gian.
console.log("Trước setTimeout");
setTimeout(() => {
console.log("Sau 2 giây!");
}, 2000);
console.log("Sau setTimeout");
Kết quả:
- "Trước setTimeout"
- "Sau setTimeout"
- (Sau 2 giây) "Sau 2 giây!"
-
Đọc file (Chạy trên Node.js)
- Đọc file là một tác vụ mất thời gian nên JavaScript xử lý bất đồng bộ.
const fs = require("fs");
console.log("Bắt đầu đọc file");
fs.readFile("data.txt", "utf8", (err, data) => {
if (err) throw err;
console.log("Nội dung file:", data);
});
console.log("Chương trình tiếp tục chạy...");
Kết quả:
- "Bắt đầu đọc file"
- "Chương trình tiếp tục chạy..."
- "Nội dung file: ..." (hiển thị sau khi đọc xong)
Kết luận:
- Khi làm việc với API, file hoặc các tác vụ tốn thời gian, lập trình bất đồng bộ giúp JavaScript chạy mượt mà hơn mà không bị chặn.
Kết luận
- Lập trình bất đồng bộ là một trong những đặc điểm quan trọng của JavaScript giúp tối ưu hiệu suất khi xử lý các tác vụ mất thời gian như gọi API, đọc file, hoặc thực hiện hẹn giờ.
- Event Loop giúp JavaScript có thể xử lý nhiều tác vụ bất đồng bộ mà không cần chạy đa luồng.
-
Ví dụ thực tế cho thấy các tác vụ như
setTimeout()
, gọi API (fetch()
), và đọc file (fs.readFile()
) đều là những thao tác bất đồng bộ hữu ích.

Với hơn 10 năm kinh nghiệm lập trình web và từng làm việc với nhiều framework, ngôn ngữ như PHP, JavaScript, React, jQuery, CSS, HTML, CakePHP, Laravel..., tôi hy vọng những kiến thức được chia sẻ tại đây sẽ hữu ích và thiết thực cho các bạn.
Xem thêm

Chào, tôi là Vũ. Đây là blog hướng dẫn lập trình của tôi.
Liên hệ công việc qua email dưới đây.
lhvuctu@gmail.com