Promises và cách hoạt động của Promise

Tạo bởi Hoàng Vũ, chỉnh sửa cuối lúc 10 tháng 3, 2025

JavaScript là ngôn ngữ bất đồng bộ (asynchronous), có nghĩa là nó không chờ một tác vụ hoàn thành trước khi thực hiện tác vụ tiếp theo.

  • Vấn đề: Khi làm việc với các tác vụ như gọi API, đọc file, xử lý dữ liệu lớn, nếu không quản lý tốt, mã có thể trở nên khó hiểu và gặp phải tình trạng callback hell (lồng quá nhiều hàm).
  • Giải pháp: Promise giúp chúng ta xử lý bất đồng bộ một cách dễ dàng hơn bằng cách cung cấp một cách tiếp cận rõ ràng và dễ đọc hơn.

Trong bài này, bạn sẽ học về cách hoạt động của Promise, các phương thức .then(), .catch(), .finally(), và cách áp dụng chúng trong thực tế.

Promises và cách hoạt động của Promise

1. Promise là gì?

  • Promise là một đối tượng đại diện cho kết quả trong tương lai của một thao tác bất đồng bộ.
  • Một Promise có thể ở một trong ba trạng thái:
    • Pending (Đang chờ xử lý): Khi Promise chưa hoàn thành.
    • Fulfilled (Thành công): Khi Promise hoàn thành công việc và trả về kết quả.
    • Rejected (Thất bại): Khi có lỗi xảy ra.

Ví dụ về các trạng thái của Promise:

let myPromise = new Promise((resolve, reject) => {
  let success = true; // Giả sử có điều kiện xác định thành công hay thất bại

  setTimeout(() => {
    if (success) {
      resolve("Dữ liệu đã tải thành công!"); // Chuyển trạng thái thành Fulfilled
    } else {
      reject("Lỗi khi tải dữ liệu!"); // Chuyển trạng thái thành Rejected
    }
  }, 2000);
});

Ở ví dụ trên, Promise sẽ mất 2 giây để hoàn thành, sau đó resolve() hoặc reject() sẽ được gọi tùy theo điều kiện.

2. Cách tạo và sử dụng new Promise()

Cú pháp cơ bản của Promise

let promise = new Promise((resolve, reject) => {
  // Xử lý bất đồng bộ (API call, đọc file, ...)
  if (/* thành công */) {
    resolve("Thành công!"); // Chuyển trạng thái thành Fulfilled
  } else {
    reject("Thất bại!"); // Chuyển trạng thái thành Rejected
  }
});

Ví dụ 1: Giả lập API tải dữ liệu thành công

function fetchData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("Dữ liệu đã được tải!");
    }, 2000);
  });
}

fetchData().then((data) => {
  console.log(data); // "Dữ liệu đã được tải!" sau 2 giây
});

Ví dụ 2: Giả lập API bị lỗi

function fetchError() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject("Không thể tải dữ liệu!");
    }, 2000);
  });
}

fetchError().catch((error) => {
  console.log(error); // "Không thể tải dữ liệu!" sau 2 giây
});

3. Sử dụng .then(), .catch().finally()

**Các phương thức quan trọng của Promise

  • .then(result => { ... }) → Xử lý khi Promise thành công.
  • .catch(error => { ... }) → Xử lý khi Promise thất bại.
  • .finally(() => { ... }) → Chạy sau khi Promise hoàn thành (dù thành công hay thất bại).

Ví dụ 3: Sử dụng .then(), .catch().finally()

function apiCall() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      let success = Math.random() > 0.5; // 50% thành công, 50% thất bại
      if (success) {
        resolve("Lấy dữ liệu thành công!");
      } else {
        reject("Lỗi kết nối đến máy chủ!");
      }
    }, 3000);
  });
}

apiCall()
  .then((result) => {
    console.log(result); // Nếu thành công, in ra kết quả
  })
  .catch((error) => {
    console.error(error); // Nếu thất bại, in ra lỗi
  })
  .finally(() => {
    console.log("Yêu cầu đã kết thúc."); // Luôn chạy
  });

Kết quả có thể là:

  • "Lấy dữ liệu thành công!"
  • "Lỗi kết nối đến máy chủ!"
  • "Yêu cầu đã kết thúc." (Luôn chạy)

4. Ứng dụng thực tế: Mô phỏng gọi API giả lập

Ví dụ 4: Giả lập gọi API lấy danh sách người dùng

function fetchUsers() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      let success = Math.random() > 0.3; // 70% thành công, 30% thất bại
      if (success) {
        resolve([
          { id: 1, name: "Alice" },
          { id: 2, name: "Bob" },
          { id: 3, name: "Charlie" },
        ]);
      } else {
        reject("Không thể tải danh sách người dùng!");
      }
    }, 2000);
  });
}

fetchUsers()
  .then((users) => {
    console.log("Danh sách người dùng:", users);
  })
  .catch((error) => {
    console.error(error);
  });

Kết quả có thể là:

  • "Danh sách người dùng: [{ id: 1, name: 'Alice' }, ...]"
  • "Không thể tải danh sách người dùng!"

Ứng dụng thực tế:

  • Gọi API lấy dữ liệu từ server.
  • Kiểm tra trạng thái đơn hàng.
  • Xác thực thông tin đăng nhập.

Kết luận

  • Promise giúp xử lý các tác vụ bất đồng bộ một cách rõ ràng và dễ đọc hơn.
  • Promise có ba trạng thái: pending, fulfilled, rejected.
  • .then(), .catch(), .finally() giúp quản lý kết quả của Promise một cách hiệu quả.
  • Promise được ứng dụng rộng rãi trong gọi API, xử lý dữ liệu bất đồng bộ, lập trình web hiện đại.
Website Logo

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.

Bình luận

Website Logo

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

Chúng Tôi Trên

Bạn đang muốn học về lập trình website?

Bạn cần nâng cao kiến thức chuyên nghiệp hơn để nâng cao cơ hội nghề nghiệp? Liên hệ