Xử lý bất đồng bộ trong JavaScript với async/await

JavaScript hoạt động trên mô hình đơn luồng, nên để tránh treo giao diện khi thực thi các tác vụ tốn thời gian như gọi API hay đọc file, lập trình viên cần sử dụng cơ chế bất đồng bộ. Từ ES2017, cú pháp asyncawait ra đời giúp viết code bất đồng bộ dễ đọc và dễ quản lý hơn nhiều so với Promise thuần hoặc callback.

Cơ chế bất đồng bộ trước async/await

Ban đầu, callback là cách phổ biến để xử lý bất đồng bộ, nhưng dẫn đến "callback hell" — tình trạng lồng ghép sâu khiến code khó bảo trì. Sau đó, Promise xuất hiện như một giải pháp thay thế, cho phép xử lý tuần tự hoặc song song với .then().catch().

function simulateApiCall() {
  return new Promise((fulfill, reject) => {
    setTimeout(() => fulfill("Kết quả trả về"), 800);
  });
}

simulateApiCall()
  .then(result => console.log(result))
  .catch(err => console.error("Lỗi:", err));

Hàm async — bao bọc Promise một cách tự nhiên

Từ khóa async đặt trước hàm sẽ khiến hàm đó luôn trả về một Promise. Nếu hàm return giá trị bình thường, Promise sẽ resolve giá trị đó. Nếu throw lỗi, Promise sẽ reject.

async function getApiResponse() {
  return "Dữ liệu từ server";
}

getApiResponse().then(data => console.log(data)); // "Dữ liệu từ server"

Await — tạm dừng để chờ kết quả

Từ khóa await chỉ dùng được bên trong hàm async. Nó tạm dừng hàm tại vị trí đó cho đến khi Promise được giải quyết, sau đó trả về giá trị resolve.

async function processResponse() {
  const response = await simulateApiCall();
  console.log("Xử lý:", response);
}

processResponse(); // In: "Xử lý: Kết quả trả về"

Xử lý lỗi với try/catch

Thay vì dùng .catch(), bạn có thể bao quanh await bằng khối try/catch để bắt lỗi một cách đồng bộ.

async function safeFetch() {
  try {
    const result = await simulateApiCall();
    console.log("Thành công:", result);
  } catch (error) {
    console.error("Thất bại:", error.message);
  }
}

Ưu điểm nổi bật

  • Code trông như đồng bộ, dễ theo dõi luồng thực thi.
  • Xử lý lỗi tập trung và trực quan hơn.
  • Loại bỏ hoàn toàn callback hell, giúp cấu trúc code phẳng và rõ ràng.

Khi nào nên dùng?

  • Các tác vụ bất đồng bộ có phụ thuộc lẫn nhau.
  • Cần làm sạch chuỗi Promise phức tạp.
  • Muốn tăng khả năng bảo trì và giảm lỗi logic.

Lưu ý quan trọng

  • Không dùng await ngoài hàm async.
  • Tránh await các Promise không bao giờ resolve (gây treo).
  • Không lạm dụng await trong vòng lặp — gây chậm hiệu năng do chạy tuần tự.

Tối ưu hiệu suất

Dùng Promise.all() để chạy song song nhiều Promise thay vì await từng cái một.

async function fetchMultipleSources() {
  try {
    const [user, posts, stats] = await Promise.all([
      fetchUser(),
      fetchPosts(),
      fetchStats()
    ]);
    return { user, posts, stats };
  } catch (err) {
    console.error("Lỗi khi lấy dữ liệu tổng hợp:", err);
  }
}

Thẻ: JavaScript async-await promise

Đăng vào ngày 2 tháng 7 lúc 17:55