Callback & Callback Hell
Bài 6 – Cơ chế callback trong Node.js và vấn đề callback hell.
Callback & Callback Hell
Callback là cơ chế bất đồng bộ truyền thống trong Node.js, cho phép chương trình xử lý tác vụ I/O mà không chặn luồng. Tuy nhiên, việc lồng nhiều callback dẫn đến hiện tượng “callback hell”, gây khó đọc và khó bảo trì. Bài học này giúp bạn hiểu cơ chế và cách tránh vấn đề này.
1. Nội dung chính
- Callback là gì và vì sao Node.js sử dụng callback
- Cách Node xử lý bất đồng bộ bằng callback
- Callback Hell và nguyên nhân
- Cách tổ chức lại code để tránh callback hell
- Các phương án thay thế: Promise và Async/Await
2. Ví dụ
Callback cơ bản
const fs = require('fs');
// Ví dụ callback cơ bản
fs.readFile('data.txt', 'utf8', (err, data) => {
if (err) return console.error(err);
console.log('Nội dung file:', data);
});
Callback Hell
// Ví dụ callback hell
setTimeout(() => {
console.log('Step 1');
setTimeout(() => {
console.log('Step 2');
setTimeout(() => {
console.log('Step 3');
}, 500);
}, 500);
}, 500);
Cách tách hàm để tránh callback hell
function step1() {
console.log('Step 1');
setTimeout(step2, 500);
}
function step2() {
console.log('Step 2');
setTimeout(step3, 500);
}
function step3() {
console.log('Step 3');
}
setTimeout(step1, 500);
3. Kiến thức trọng tâm
- Callback là nền tảng của bất đồng bộ trong Node.js
- Callback Hell xuất hiện khi callback lồng nhau nhiều cấp
- Có thể tránh callback hell bằng cách: tách hàm nhỏ, sử dụng Promise hoặc Async/Await
4. Bài tập nhanh
- Viết chương trình đọc 2 file liên tiếp bằng callback lồng nhau:
const fs = require('fs');
fs.readFile('file1.txt', 'utf8', (err, data1) => {
if (err) return console.error(err);
console.log('File 1:', data1);
fs.readFile('file2.txt', 'utf8', (err, data2) => {
if (err) return console.error(err);
console.log('File 2:', data2);
});
});
-
Tối ưu lại code theo hướng chia nhỏ thành các hàm riêng
-
Thử chuyển đoạn callback hell sang Promise để so sánh:
// Sử dụng Promise
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
delay(500)
.then(() => {
console.log('Step 1');
return delay(500);
})
.then(() => {
console.log('Step 2');
return delay(500);
})
.then(() => {
console.log('Step 3');
});
5. Kết luận
Callback giúp Node.js vận hành bất đồng bộ, nhưng khi lạm dụng sẽ gây phức tạp hóa logic. Chọn kiến trúc phù hợp hoặc sử dụng Promise/Async-Await sẽ giúp code rõ ràng và dễ bảo trì hơn.