NTM Solutions

Chủ Nhật, 2 tháng 8, 2026

Bài 12 — Promise trong Node.js

Thuộc phần 3: Asynchronous Programming


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

Sau bài này, bạn sẽ hiểu:

  • Promise là gì.

  • Vì sao Promise ra đời.

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

  • Cách tạo Promise.

  • .then()

  • .catch()

  • .finally()

  • Promise Chaining.

  • Promise trong Node.js thực tế.


Callback Hell

Ở bài trước chúng ta đã học Callback.

Ví dụ:

login(function(user){

    getProfile(user, function(profile){

        getPosts(profile, function(posts){

            console.log(posts);

        });

    });

});

Khi chương trình lớn lên, callback lồng callback sẽ khiến code:

  • Khó đọc

  • Khó bảo trì

  • Khó bắt lỗi

Đây gọi là:

Callback Hell

Hay còn gọi vui là:

Pyramid of Doom

Ví dụ:

step1(function(){

    step2(function(){

        step3(function(){

            step4(function(){

                step5(function(){

                });

            });

        });

    });

});

Nhìn giống một kim tự tháp.

Đây chính là lý do Promise ra đời.


Promise là gì?

Promise là một đối tượng đại diện cho kết quả của một tác vụ bất đồng bộ, có thể thành công hoặc thất bại trong tương lai.

Hiểu đơn giản:

Promise giống như một "tờ giấy hứa".

Ví dụ:

Bạn đặt hàng online.

Ngay lúc đặt:

  • Chưa có hàng

  • Chưa biết khi nào tới

Shop chỉ hứa:

"Tôi sẽ giao."

Sau vài ngày:

  • giao thành công

  • hoặc giao thất bại

Đó chính là Promise.


Promise có 3 trạng thái

Pending

Đang chờ xử lý.

Ví dụ:

Đang tải dữ liệu...

Fulfilled

Thành công.

Ví dụ:

Đã lấy dữ liệu thành công.

Rejected

Thất bại.

Ví dụ:

Mất kết nối.

Minh họa:

           Pending
           /     \
          /       \
 Fulfilled      Rejected

Cú pháp Promise

const promise = new Promise(function(resolve, reject){

});

Hoặc dùng Arrow Function:

const promise = new Promise((resolve, reject) => {

});

Trong đó:

  • resolve() → thành công

  • reject() → thất bại


Promise thành công

Ví dụ:

const promise = new Promise((resolve, reject) => {

    resolve("Xin chào Node.js");

});

Lấy kết quả:

promise.then(function(data){

    console.log(data);

});

Kết quả:

Xin chào Node.js

Promise thất bại

const promise = new Promise((resolve, reject) => {

    reject("Có lỗi xảy ra");

});

Xử lý lỗi:

promise.catch(function(error){

    console.log(error);

});

Kết quả:

Có lỗi xảy ra

then()

.then() chạy khi Promise thành công.

Ví dụ:

const promise = new Promise((resolve) => {

    resolve(100);

});

promise.then((number) => {

    console.log(number);

});

Kết quả:

100

catch()

.catch() chạy khi Promise bị lỗi.

Ví dụ:

const promise = new Promise((resolve, reject) => {

    reject("Server Error");

});

promise.catch((error)=>{

    console.log(error);

});

Kết quả:

Server Error

finally()

.finally() luôn chạy dù thành công hay thất bại.

Ví dụ:

promise
.then(data=>{

    console.log(data);

})
.catch(err=>{

    console.log(err);

})
.finally(()=>{

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

});

Kết quả:

Hoàn thành.

Rất hữu ích khi:

  • Tắt Loading

  • Đóng Database

  • Giải phóng tài nguyên

  • Ghi log


Promise giả lập thời gian chờ

Ví dụ:

const promise = new Promise((resolve)=>{

    setTimeout(()=>{

        resolve("Đã xong.");

    },3000);

});

Lấy dữ liệu:

promise.then((data)=>{

    console.log(data);

});

Sau 3 giây:

Đã xong.

Promise Chaining

Promise có thể nối tiếp nhau.

Ví dụ:

Promise.resolve(5)

.then(number=>{

    return number * 2;

})

.then(number=>{

    return number + 10;

})

.then(number=>{

    console.log(number);

});

Kết quả:

20

Mỗi .then() nhận kết quả của .then() trước đó.


Trả về Promise trong then()

Ví dụ:

Promise.resolve(10)

.then(number=>{

    return new Promise((resolve)=>{

        resolve(number * 3);

    });

})

.then(result=>{

    console.log(result);

});

Kết quả:

30

Promise sẽ tự động chờ Promise mới hoàn thành trước khi chuyển sang .then() tiếp theo.


Promise với setTimeout()

Ví dụ:

function sleep(ms){

    return new Promise((resolve)=>{

        setTimeout(resolve, ms);

    });

}

sleep(2000)

.then(()=>{

    console.log("2 giây đã trôi qua.");

});

Đây là một mẫu rất phổ biến trong lập trình Node.js.


Promise trong File System

Từ Node.js hiện đại, nhiều API đã hỗ trợ Promise.

Ví dụ:

import { readFile } from "node:fs/promises";

readFile("hello.txt", "utf8")

.then(data=>{

    console.log(data);

})
.catch(err=>{

    console.log(err);

});

Không còn phải truyền callback như trước.


Promise trong Fetch API

Node.js hiện đại đã tích hợp sẵn fetch().

Ví dụ:

fetch("https://jsonplaceholder.typicode.com/posts/1")

.then(response => response.json())

.then(data => {

    console.log(data);

})

.catch(error => {

    console.log(error);

});

Quy trình xử lý:

fetch()
    ↓
Response
    ↓
response.json()
    ↓
Object JavaScript

Đây là cách gọi API rất phổ biến trong các ứng dụng Node.js và trình duyệt.


Promise.all()

Chạy nhiều Promise song song.

Ví dụ:

Promise.all([

    Promise.resolve("Node.js"),

    Promise.resolve("Express"),

    Promise.resolve("Prisma")

])

.then(data=>{

    console.log(data);

});

Kết quả:

[
  'Node.js',
  'Express',
  'Prisma'
]

Nếu một Promise thất bại thì toàn bộ Promise.all() sẽ bị từ chối (reject).


Promise.race()

Trả về Promise hoàn thành đầu tiên.

Ví dụ:

Promise.race([

    new Promise(resolve => setTimeout(() => resolve("A"), 3000)),

    new Promise(resolve => setTimeout(() => resolve("B"), 1000))

])

.then(data => {

    console.log(data);

});

Kết quả:

B

Promise.race() hữu ích khi cần giới hạn thời gian chờ hoặc chọn kết quả phản hồi nhanh nhất.


Promise.any()

Trả về Promise thành công đầu tiên.

Ví dụ:

Promise.any([

    Promise.reject("Lỗi 1"),

    Promise.resolve("Đã thành công"),

    Promise.resolve("Dự phòng")

])

.then(result => {

    console.log(result);

});

Kết quả:

Đã thành công

Nếu tất cả Promise đều thất bại thì Promise.any() mới phát sinh lỗi.


Promise.allSettled()

Chờ tất cả Promise kết thúc, bất kể thành công hay thất bại.

Ví dụ:

Promise.allSettled([

    Promise.resolve("OK"),

    Promise.reject("Lỗi")

])

.then(results => {

    console.log(results);

});

Kết quả:

[
  { status: "fulfilled", value: "OK" },
  { status: "rejected", reason: "Lỗi" }
]

Rất phù hợp khi cần tổng hợp kết quả của nhiều tác vụ độc lập.


Khi nào nên dùng Promise?

Nên dùng Promise khi:

  • Đọc/Ghi file.

  • Gọi REST API.

  • Truy vấn cơ sở dữ liệu.

  • Upload file.

  • Xử lý nhiều tác vụ bất đồng bộ.

  • Làm việc với các thư viện hiện đại của Node.js.


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

❌ Quên xử lý lỗi bằng .catch().

promise.then(data => {
    console.log(data);
});

Nếu Promise bị từ chối (reject), lỗi có thể không được xử lý.


❌ Không return giá trị trong .then().

Promise.resolve(5)
.then(number => {
    number * 2;
})
.then(result => {
    console.log(result);
});

Kết quả:

undefined

Cần viết:

return number * 2;

❌ Tạo Promise không cần thiết.

Ví dụ:

return new Promise((resolve) => {
    resolve(data);
});

Có thể rút gọn:

return Promise.resolve(data);

Hoặc đơn giản:

return data;

Tổng kết

Trong bài học này, bạn đã nắm được cách Promise giúp giải quyết hạn chế của Callback bằng cách tổ chức mã nguồn rõ ràng và dễ bảo trì hơn. Bạn đã biết ba trạng thái của Promise, cách sử dụng .then(), .catch(), .finally(), kết hợp nhiều Promise với Promise.all(), Promise.race(), Promise.any(), Promise.allSettled(), cũng như ứng dụng Promise trong đọc file và gọi API.

Ở bài tiếp theo, chúng ta sẽ học Bài 13 — Async / Await, cú pháp hiện đại giúp viết mã bất đồng bộ theo phong cách gần giống mã đồng bộ, ngắn gọn và dễ đọc hơn.

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

Đăng nhận xét

Facebook Youtube RSS