NTM Solutions

Thứ Hai, 27 tháng 7, 2026

🚀 Node.js LTS (2026) — Bài 11: Callback - Nền tảng của lập trình bất đồng bộ 🔄

"Trước khi có Promise và Async/Await, Callback chính là cách Node.js xử lý các tác vụ bất đồng bộ. Hiểu Callback sẽ giúp bạn hiểu vì sao JavaScript hiện đại được thiết kế như ngày nay."


🎯 Mục tiêu bài học

Sau bài này bạn sẽ:

  • Hiểu Callback là gì.

  • Phân biệt Callback đồng bộ và bất đồng bộ.

  • Biết cách truyền Callback vào hàm.

  • Hiểu Callback Hell là gì.

  • Biết khi nào nên dùng Callback.

  • Hiểu vì sao Promise và Async/Await ra đời.


Callback là gì?

Callback là một hàm được truyền vào làm tham số của một hàm khác để được gọi lại (call back) khi cần.

Ví dụ đơn giản:

function hello(callback) {

    console.log("Xin chào");

    callback();

}

hello(() => {

    console.log("Node.js");

});

Kết quả

Xin chào

Node.js

Ở đây:

  • hello() là hàm chính.

  • Hàm mũi tên được truyền vào chính là Callback.


Vì sao cần Callback?

Giả sử bạn cần:

  1. Đọc file.

  2. Sau khi đọc xong mới xử lý dữ liệu.

Không thể:

readFile();

xuLy();

vì chưa chắc file đã đọc xong.

Thay vào đó:

readFile(() => {

    xuLy();

});

Chỉ khi hoàn thành, Callback mới được gọi.


Callback đồng bộ

Ví dụ

function tinhTong(a, b, callback) {

    const tong = a + b;

    callback(tong);

}

tinhTong(5, 8, (kq) => {

    console.log(kq);

});

13

Ở đây Callback được gọi ngay lập tức, nên đây là Callback đồng bộ (Synchronous Callback).


Callback bất đồng bộ

Ví dụ

setTimeout(() => {

    console.log("Đã xong");

}, 2000);

console.log("Đang chờ...");

Đang chờ...

(sau 2 giây)

Đã xong

Callback chỉ chạy sau khi hết thời gian chờ.


Callback với fs

Ví dụ

import fs from "node:fs";

fs.readFile(
    "data.txt",
    "utf8",
    (err, data) => {

        if (err) {

            console.log(err);

            return;

        }

        console.log(data);

    }
);

Xin chào Node.js

Đây là kiểu Callback rất phổ biến trong Node.js.


Error-first Callback

Phần lớn API của Node.js sử dụng quy ước:

(err, data)

Ví dụ

fs.readFile(
    "abc.txt",
    "utf8",
    (err, data) => {

        if (err) {

            console.log(err);

            return;

        }

        console.log(data);

    }
);

Nếu lỗi:

ENOENT

Nếu thành công:

Nội dung file

Tham số đầu tiên luôn là Error.

Đây được gọi là:

Error-first Callback


Callback nhiều cấp

Ví dụ

login(() => {

    loadProfile(() => {

        loadOrders(() => {

            console.log("Hoàn thành");

        });

    });

});

Nhìn vẫn còn đơn giản.

Nhưng nếu dự án lớn:

login(() => {

    profile(() => {

        avatar(() => {

            order(() => {

                payment(() => {

                    history(() => {

                        message(() => {

                            notify(() => {

                            });

                        });

                    });

                });

            });

        });

    });

});

Code bắt đầu lệch sang bên phải rất nhiều.


Callback Hell

Đây là hiện tượng nhiều Callback lồng nhau.

login()

↓

profile()

↓

order()

↓

payment()

↓

email()

↓

log()

↓

notification()

Hay còn được gọi vui là:

Pyramid of Doom (Kim tự tháp địa ngục).


Nhược điểm của Callback Hell

  • Khó đọc.

  • Khó bảo trì.

  • Debug khó.

  • Dễ quên xử lý lỗi.

  • Khó tái sử dụng.

Đó là lý do Promise và Async/Await trở thành lựa chọn phổ biến trong JavaScript hiện đại.


Callback có phải luôn xấu?

Không.

Nhiều API của Node.js vẫn dùng Callback vì:

  • Đơn giản.

  • Hiệu năng tốt.

  • Không cần tạo Promise.

Ví dụ

fs.readFile(
    "data.txt",
    "utf8",
    callback
);

Hoặc

server.listen(
    3000,
    () => {

        console.log("Server running");

    }
);

Callback và Event

Hai khái niệm này thường bị nhầm.

Callback

download(() => {

    console.log("Xong");

});

Một Callback.


Event

event.on(
    "message",
    () => {

        console.log("Có tin nhắn");

    }
);

Có thể có nhiều Listener.


Callback và Promise

Callback

readFile((err, data) => {

});

Promise

readFile()

.then(data => {

});

Promise giúp code phẳng hơn và dễ kết hợp nhiều tác vụ bất đồng bộ.


Callback và Async/Await

Promise

await readFile();

Code nhìn gần giống:

const data =
docFile();

Dễ đọc hơn rất nhiều.


Ví dụ thực tế

Giả sử tải thông tin người dùng.

function getUser(callback){

    setTimeout(()=>{

        callback({

            name:"An"

        });

    },1000);

}

getUser((user)=>{

    console.log(user.name);

});

An

Mặc dù mất 1 giây để lấy dữ liệu, chương trình vẫn không bị chặn.


Luồng hoạt động

Gọi hàm

↓

Thực hiện công việc

↓

Hoàn thành

↓

Gọi Callback

Đây chính là cơ chế nền tảng của rất nhiều API bất đồng bộ trong Node.js.


Những lỗi thường gặp

Quên xử lý Error

Sai

fs.readFile(
"data.txt",

(err,data)=>{

console.log(data);

}
);

Nên

if(err){

return;

}

trước khi sử dụng data.


Callback Hell

A(()=>{

B(()=>{

C(()=>{

D(()=>{

});

});

});

});

Nên cân nhắc Promise hoặc Async/Await khi chuỗi xử lý trở nên phức tạp.


Gọi Callback nhiều lần

callback();

callback();

Có thể gây lỗi logic hoặc khiến kết quả bị xử lý lặp lại ngoài ý muốn.


Quên gọi Callback

function test(cb){

}

Nếu không gọi:

cb();

phần mã đang chờ Callback sẽ không bao giờ được thực thi.


Khi nào dùng Callback?

Phù hợp với:

  • API cũ.

  • Event.

  • Timer.

  • Stream.

  • HTTP Server.

  • Một số module lõi của Node.js.

Trong các dự án mới, Callback vẫn xuất hiện nhưng thường được thay thế hoặc bọc bởi Promise khi chuỗi xử lý trở nên phức tạp.


Bảng tổng hợp

Khái niệmÝ nghĩa
CallbackHàm truyền vào hàm khác
Sync CallbackChạy ngay
Async CallbackChạy sau
Error-first Callback(err, data)
Callback HellCallback lồng nhau
PromiseGiải quyết Callback Hell
Async/AwaitCú pháp hiện đại cho Promise

Tổng kết

Callback là nền tảng của lập trình bất đồng bộ trong Node.js. Mặc dù ngày nay Promise và Async/Await được sử dụng phổ biến hơn, việc hiểu Callback vẫn rất quan trọng vì nhiều API cốt lõi của Node.js và không ít thư viện vẫn hỗ trợ hoặc sử dụng mô hình này.

Nắm vững Callback sẽ giúp bạn hiểu rõ cách hoạt động của Event Loop, Promise và Async/Await trong các bài học tiếp theo.


Bài tiếp theo

👉 Bài 12 — Promise

Bạn sẽ học:

  • Promise là gì.

  • Ba trạng thái của Promise.

  • resolve()reject().

  • then(), catch()finally().

  • Vì sao Promise giúp mã nguồn dễ đọc, dễ bảo trì và giải quyết hiệu quả Callback Hell.

Không có nhận xét nào:

Đăng nhận xét

Facebook Youtube RSS