Fetch API và AJAX

Fetch API là gì?

Fetch API cho phép JavaScript gửi HTTP request và nhận response mà không cần tải lại trang. Đây là cách hiện đại thay thế cho XMLHttpRequest (XHR).

fetch('https://api.example.com/data')
  .then(response => response.json())  // parse JSON
  .then(data => console.log(data))    // xử lý dữ liệu
  .catch(error => console.error(error));

Cú pháp với async / await

async function getData() {
  try {
    const response = await fetch('https://api.example.com/data');
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}`);
    }
    const data = await response.json();
    return data;
  } catch (error) {
    console.error('Lỗi:', error);
  }
}

Luôn kiểm tra response.okfetch() chỉ reject khi có lỗi mạng, không reject với HTTP 4xx/5xx.

GET vs POST

GET (đọc dữ liệu):

const response = await fetch('https://api.example.com/users');

POST (gửi dữ liệu):

const response = await fetch('https://api.example.com/posts', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ title: 'Bài mới', body: 'Nội dung...', userId: 1 })
});

CORS (Cross-Origin Resource Sharing)

Trình duyệt chặn request đến domain khác trừ khi server cho phép qua header Access-Control-Allow-Origin. Sử dụng API hỗ trợ CORS (ví dụ: JSONPlaceholder, OpenWeatherMap) hoặc proxy backend.

Ví dụ: Tải thông tin người dùng

Kết quả
<div style="font-family:sans-serif">
  <button id="loadUserBtn"
    style="padding:0.5rem 1.25rem;background:#4472c4;color:white;
           border:none;border-radius:6px;cursor:pointer;font-size:1rem">
    Tải người dùng #1
  </button>
  <div id="userCard"
    style="margin-top:1rem;padding:1rem;background:#f8f9fa;
           border-radius:8px;min-height:60px;border:1px solid #dee2e6">
    Nhấn button để tải dữ liệu...
  </div>
</div>
document.getElementById('loadUserBtn').addEventListener('click', async function() {
  const card = document.getElementById('userCard');
  card.textContent = 'Đang tải...';

  try {
    const res  = await fetch('https://jsonplaceholder.typicode.com/users/1');
    if (!res.ok) throw new Error('HTTP ' + res.status);
    const user = await res.json();

    card.innerHTML = `
      <h3 style="margin:0 0 0.5rem">${user.name}</h3>
      <p style="margin:0.25rem 0">📧 ${user.email}</p>
      <p style="margin:0.25rem 0">📞 ${user.phone}</p>
      <p style="margin:0.25rem 0">🌐 ${user.website}</p>
      <p style="margin:0.25rem 0">🏢 ${user.company.name}</p>
    `;
  } catch (err) {
    card.innerHTML = '<span style="color:red">Lỗi: ' + err.message + '</span>';
  }
});

Ví dụ: Tải danh sách bài viết

Kết quả
<div style="font-family:sans-serif">
  <button id="loadPostsBtn"
    style="padding:0.5rem 1.25rem;background:#2ecc71;color:white;
           border:none;border-radius:6px;cursor:pointer;font-size:1rem">
    Tải 5 bài viết
  </button>
  <div id="postGrid" style="margin-top:1rem;display:grid;gap:0.75rem"></div>
</div>
.post-card {
  background: white;
  border: 1px solid #dee2e6;
  border-radius: 8px;
  padding: 0.75rem 1rem;
  box-shadow: 0 1px 3px rgba(0,0,0,.08);
}
.post-card h4 { margin: 0 0 0.35rem; color: #4472c4; font-size: 0.95rem; }
.post-card p  { margin: 0; color: #555; font-size: 0.85rem; }
document.getElementById('loadPostsBtn').addEventListener('click', async function() {
  const grid = document.getElementById('postGrid');
  grid.innerHTML = '<p style="color:#999">Đang tải...</p>';

  try {
    const res   = await fetch('https://jsonplaceholder.typicode.com/posts?_limit=5');
    const posts = await res.json();

    grid.innerHTML = posts.map(p => `
      <div class="post-card">
        <h4>${p.title}</h4>
        <p>${p.body.slice(0, 80)}...</p>
      </div>
    `).join('');
  } catch (err) {
    grid.innerHTML = '<span style="color:red">Lỗi: ' + err.message + '</span>';
  }
});

Bình luận