Bài 7. Bất đồng bộ và fetch

Nhiều việc mất thời gian như tải dữ liệu từ mạng. JavaScript xử lý chúng bằng Promise và async/await mà không làm đơ trang.

40 phútTrung cấp
Bạn sẽ học được
  • Hiểu bất đồng bộ là gì
  • Dùng Promise và async/await
  • Gọi API bằng fetch
  • Xử lý lỗi mạng
Thuật ngữ cần biết
Bất đồng bộ
Việc chạy ngầm, kết quả có sau, chương trình không phải chờ.
Promise
Đối tượng đại diện kết quả sẽ có trong tương lai: đang chờ, thành công, hoặc lỗi.
API
Địa chỉ cung cấp dữ liệu cho chương trình khác dùng.
async/await
Cú pháp viết mã bất đồng bộ trông như mã tuần tự.

Khái niệm và lý thuyết

JavaScript chỉ có một luồng thực thi, nghĩa là tại một thời điểm chỉ làm một việc. Nếu chờ mạng 3 giây trong luồng chính thì trang đơ. Giải pháp là bất đồng bộ: giao việc chậm cho trình duyệt, tiếp tục chạy mã khác, khi có kết quả thì đưa hàm xử lý vào hàng đợi để vòng lặp sự kiện (event loop) chạy khi luồng rảnh.

Có ba cách viết bất đồng bộ theo thời gian: callback (dễ lồng nhau thành "địa ngục callback"), Promise (đối tượng đại diện kết quả tương lai với ba trạng thái: pending, fulfilled, rejected) và async/await (cú pháp đẹp trên nền Promise). await chỉ tạm dừng hàm async đó, không chặn cả chương trình.

API HTTP: mỗi yêu cầu có phương thức (GET lấy dữ liệu, POST gửi dữ liệu), địa chỉ, và phản hồi có mã trạng thái (200 thành công, 404 không thấy, 500 lỗi máy chủ). Hàm fetch trả về Promise.

Vì sao cần bất đồng bộ?

Nếu tải ảnh mất 3 giây mà trang phải đứng chờ thì rất khó chịu. Trình duyệt giao việc đó cho nền, khi xong sẽ báo cho mã của bạn.

Gửi yêu cầuTiếp tục làm việc khácCó kết quảChạy then/await

fetch và async/await

async function layBaiViet() {
  try {
    const res = await fetch("https://jsonplaceholder.typicode.com/posts/1");
    if (!res.ok) throw new Error("Lỗi " + res.status);
    const data = await res.json();
    console.log(data.title);
  } catch (loi) {
    console.error("Không tải được:", loi.message);
  }
}
layBaiViet();

Ví dụ: lấy dữ liệu từ một API công khai

async function layViecCanLam() {
  try {
    const res = await fetch("https://jsonplaceholder.typicode.com/todos/1");
    const data = await res.json();
    console.log(data.title);
  } catch (loi) {
    console.log("Không tải được:", loi);
  }
}
layViecCanLam();

Trang JSONPlaceholder cung cấp dữ liệu mẫu miễn phí để bạn luyện tập mà không cần tự dựng máy chủ. Hãy luôn bọc try/catch khi gọi mạng vì kết nối có thể thất bại bất cứ lúc nào.

Promise nhiều việc cùng lúc

const [a, b] = await Promise.all([
  fetch("/api/a").then(r => r.json()),
  fetch("/api/b").then(r => r.json())
]);

Chạy song song nhanh hơn chờ từng việc xong mới làm việc kế tiếp.

Tình huống: Hiển thị thời tiết

Gọi API thời tiết, hiện nhiệt độ lên trang và báo lỗi khi mất mạng. Mô hình: fetch → json() → gắn vào DOM → catch báo lỗi.

Mẹo hay

Luôn kiểm tra res.ok vì fetch chỉ báo lỗi khi mất mạng, không báo khi máy chủ trả 404 hoặc 500.

Lưu ý

Quên await sẽ nhận về Promise chứ không phải dữ liệu.

Thực hành
  1. Gọi API công khai và in 5 bài viết đầu tiên lên trang.
  2. Thêm thông báo "Đang tải..." trước khi có dữ liệu.
  3. Thử ngắt mạng để xem khối catch hoạt động.
Tóm tắt bài học
  • Bất đồng bộ giữ cho trang không bị đơ.
  • async/await làm mã dễ đọc.
  • fetch cần kiểm tra res.ok và bọc try/catch.