Mục lục

    Nếu bạn là một lập trình viên web, việc tương tác với máy chủ (server) để lấy hoặc gửi dữ liệu là một tác vụ không thể thiếu. Trước đây, XMLHttpRequest là công cụ chủ đạo, nhưng cú pháp của nó khá phức tạp và dài dòng. Ngày nay, Fetch API đã nổi lên như một tiêu chuẩn hiện đại, mạnh mẽ và dễ sử dụng hơn rất nhiều.

    Vậy cụ thể Fetch là gì? Tại sao nó lại được ưa chuộng đến vậy? Hãy cùng tìm hiểu chi tiết từ A-Z trong bài viết này.

    Fetch là gì?

    Fetch (hay Fetch API) là một giao diện (interface) hiện đại được tích hợp sẵn trong JavaScript để thực hiện các yêu cầu mạng (network requests) đến một máy chủ từ trình duyệt. Nó cho phép bạn lấy (fetch) tài nguyên (ví dụ: dữ liệu JSON, hình ảnh, file HTML) một cách bất đồng bộ qua mạng.

    Fetch là gì
    Fetch là gì

    Điểm cốt lõi làm nên sức mạnh của Fetch là nó được xây dựng dựa trên Promise. Điều này giúp xử lý các tác vụ bất đồng bộ một cách gọn gàng, dễ đọc và tránh được “Callback Hell” – một vấn đề nhức nhối của XMLHttpRequest.

    Nói một cách đơn giản, Fetch là công cụ giúp “cô phục vụ” JavaScript của bạn đi đến “nhà bếp” (server), lấy “món ăn” (dữ liệu) và mang về “bàn” (ứng dụng web của bạn) một cách hiệu quả.

    Hãy cùng phân tích chi tiết từng khía cạnh của khái niệm này.

    Triết lý thiết kế: Sự thay thế cho XMLHttpRequest (XHR)

    Để hiểu Fetch, ta cần biết “nỗi đau” mà nó giải quyết. Trước đây, XMLHttpRequest là cách duy nhất để gửi yêu cầu mạng từ JavaScript.

    • Vấn đề của XHR:
      • Cú pháp rườm rà: Bạn phải khởi tạo đối tượng, lắng nghe nhiều sự kiện (onload, onerror, onprogress), gọi open() rồi send().
      • Callback Hell: Logic xử lý bất đồng bộ dựa hoàn toàn vào callback, dễ dàng dẫn đến code lồng vào nhau khó đọc và khó bảo trì.
      • Thiếu nhất quán: Việc xử lý headers, body và các trạng thái không trực quan.
    • Triết lý của Fetch ra đời để giải quyết các vấn đề trên:
      • Promise-based: Đây là thay đổi cốt lõi. Mọi thứ trong Fetch đều xoay quanh Promise, cho phép một luồng xử lý bất đồng bộ mạch lạc, dễ đọc qua .then(), .catch(), và đặc biệt là cú pháp async/await.
      • Mô-đun hóa và Trừu tượng hóa: Thay vì một đối tượng XHR làm tất cả, Fetch chia nhỏ các thành phần của một giao dịch HTTP thành các đối tượng riêng biệt và mạnh mẽ: Request, Response, Headers.
      • Làm việc với Streams: Body của RequestResponse được thiết kế dưới dạng luồng dữ liệu (Streams). Điều này cực kỳ hiệu quả khi làm việc với các file lớn, cho phép xử lý dữ liệu ngay khi nó bắt đầu được tải về thay vì phải chờ toàn bộ file.

    Hệ sinh thái các thành phần của Fetch API

    Khi bạn gọi fetch(), thực chất bạn đang tương tác với một tập hợp các API sau:

    a. fetch() function

    Đây là điểm khởi đầu, một hàm toàn cục (window.fetch()) có sẵn trong trình duyệt.

    • Nó nhận đầu vào là một tài nguyên (URL hoặc một đối tượng Request).
    • Nó ngay lập tức trả về một Promise. Promise này sẽ được “resolve” (hoàn thành) khi trình duyệt nhận được phản hồi chứa headers từ server. Lưu ý: ở thời điểm này, phần body (nội dung) của phản hồi có thể vẫn chưa được tải về hết.

    b. Headers object

    Đây là một giao diện chuyên dụng để làm việc với các HTTP headers. Nó cung cấp các phương thức tiện lợi để truy vấn và thay đổi headers một cách an toàn và nhất quán.

    • headers.append(name, value): Thêm một header mới.
    • headers.get(name): Lấy giá trị của một header.
    • headers.has(name): Kiểm tra sự tồn tại của header.
    • headers.set(name, value): Thiết lập hoặc ghi đè giá trị header.
    JavaScript
    const myHeaders = new Headers();
    myHeaders.append('Content-Type', 'application/json');
    myHeaders.append('X-Custom-Header', 'MyValue');

    c. Request object

    Đối tượng này đại diện cho một yêu cầu mạng sắp được gửi đi. Nó chứa tất cả thông tin về yêu cầu đó.

    • url: Điểm cuối API.
    • method: GET, POST, PUT, DELETE
    • headers: Một đối tượng Headers.
    • body: Dữ liệu gửi đi (có thể là string, FormData, Blob…).
    • mode: Chế độ CORS ('cors', 'no-cors', 'same-origin').

    Bạn có thể tạo một đối tượng Request một cách tường minh và truyền nó vào fetch(). Điều này rất hữu ích khi bạn muốn tái sử dụng hoặc thay đổi cấu hình request ở nhiều nơi.

    JavaScript
    const myRequest = new Request('/api/data', {
      method: 'POST',
      headers: myHeaders,
      body: JSON.stringify({ key: 'value' })
    });
    
    fetch(myRequest);

    d. Response object

    Đây là đối tượng đại diện cho phản hồi từ server. Đây là kết quả mà Promise của fetch() trả về.

    • status: Mã trạng thái HTTP (ví dụ: 200, 404).
    • statusText: Chuỗi thông báo trạng thái (ví dụ: "OK", "Not Found").
    • ok: Một thuộc tính boolean cực kỳ quan trọng. Nó là true nếu status nằm trong khoảng 200-299, và false nếu ngược lại. Đây là cách chuẩn để kiểm tra một request có thành công hay không.
    • headers: Một đối tượng Headers chứa các header của phản hồi.
    • body: Đây là một ReadableStream (luồng có thể đọc). Vì nó là một luồng, bạn không thể truy cập trực tiếp nội dung mà phải dùng các phương thức được cung cấp để đọc hết luồng đó.

    Xem thêm:

    Tại sao nên sử dụng Fetch?

    Fetch API mang lại nhiều ưu điểm vượt trội so với các phương pháp cũ:

    Tại sao nên sử dụng Fetch
    Tại sao nên sử dụng Fetch
    • ✅ Cú pháp hiện đại và sạch sẽ: Code ngắn gọn, dễ hiểu hơn rất nhiều so với XMLHttpRequest.
    • ✅ Dựa trên Promise: Giúp quản lý luồng bất đồng bộ một cách mạch lạc, dễ dàng kết hợp với async/await.
    • ✅ Linh hoạt và mạnh mẽ: Dễ dàng tùy chỉnh các yêu cầu HTTP (GET, POST, PUT, DELETE) với các headers, body, và nhiều tùy chọn khác.
    • ✅ Tích hợp sẵn trong trình duyệt: Bạn không cần phải cài đặt thêm bất kỳ thư viện bên ngoài nào để sử dụng.

    Hướng dẫn sử dụng Fetch API (Cú pháp và Ví dụ)

    Hướng dẫn sử dụng Fetch API
    Hướng dẫn sử dụng Fetch API

    1. Cú pháp cơ bản

    Cú pháp của fetch() rất đơn giản:

    JavaScript
    fetch(url, [options])
      .then(response => {
        // Xử lý đối tượng response trả về
      })
      .then(data => {
        // Xử lý dữ liệu cuối cùng
      })
      .catch(error => {
        // Xử lý khi có lỗi xảy ra
      });
    • url: Đường dẫn (endpoint) của tài nguyên bạn muốn lấy.
    • options (tùy chọn): Một đối tượng để tùy chỉnh yêu cầu như method, headers, body. Nếu bỏ qua, fetch sẽ mặc định thực hiện một yêu cầu GET.

    2. Ví dụ: Lấy dữ liệu với GET (Request cơ bản nhất)

    Đây là trường hợp sử dụng phổ biến nhất, dùng để yêu cầu dữ liệu từ một API.

    JavaScript
    // URL của API công khai để lấy danh sách người dùng
    const apiUrl = 'https://jsonplaceholder.typicode.com/users';
    
    fetch(apiUrl)
      // 1. fetch trả về một Promise. Khi Promise này hoàn thành,
      // chúng ta nhận được đối tượng 'response'.
      .then(response => {
        // 2. Kiểm tra xem request có thành công không (status code 200-299).
        if (!response.ok) {
          throw new Error('Network response was not ok ' + response.statusText);
        }
        // 3. Chuyển đổi response sang định dạng JSON.
        // .json() cũng trả về một Promise.
        return response.json();
      })
      // 4. Khi Promise từ .json() hoàn thành, chúng ta nhận được dữ liệu thực sự.
      .then(users => {
        console.log('Danh sách người dùng:', users);
        // Giờ bạn có thể dùng dữ liệu 'users' để hiển thị ra giao diện.
      })
      // 5. Bắt lỗi nếu có bất kỳ lỗi nào xảy ra trong chuỗi Promise.
      .catch(error => {
        console.error('There has been a problem with your fetch operation:', error);
      });

    3. Ví dụ: Gửi dữ liệu với POST

    Khi bạn muốn tạo một tài nguyên mới (ví dụ: đăng ký tài khoản, đăng bài viết), bạn sẽ dùng phương thức POST.

    JavaScript
    const apiUrl = 'https://jsonplaceholder.typicode.com/posts';
    
    // Dữ liệu bạn muốn gửi đi
    const newPost = {
      title: 'foo',
      body: 'bar',
      userId: 1,
    };
    
    // Tùy chọn cho yêu cầu POST
    const options = {
      method: 'POST', // Phương thức là POST
      headers: {
        // Khai báo kiểu dữ liệu của body là JSON
        'Content-Type': 'application/json',
      },
      // Chuyển đổi đối tượng JavaScript thành một chuỗi JSON
      body: JSON.stringify(newPost),
    };
    
    fetch(apiUrl, options)
      .then(response => response.json())
      .then(data => {
        console.log('Dữ liệu đã được tạo thành công:', data);
      })
      .catch(error => {
        console.error('Lỗi khi gửi dữ liệu:', error);
      });

    4. Kết hợp với async/await (Cú pháp hiện đại)

    Sử dụng async/await giúp code của bạn trông giống như code đồng bộ, dễ đọc và dễ bảo trì hơn.

    JavaScript
    async function fetchUsers() {
      const apiUrl = 'https://jsonplaceholder.typicode.com/users';
    
      try {
        const response = await fetch(apiUrl);
    
        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }
    
        const users = await response.json();
        console.log(users);
      } catch (error) {
        console.error('Không thể lấy dữ liệu người dùng:', error);
      }
    }
    
    // Gọi hàm để thực thi
    fetchUsers();

    So sánh Fetch vs Axios vs XMLHttpRequest

    Đây là câu hỏi mà rất nhiều lập trình viên quan tâm.

    Tính năngFetch APIAxiosXMLHttpRequest (XHR)
    Cú pháp💡 Hiện đại, dựa trên Promise.✅ Rất hiện đại, dựa trên Promise.낡 Cũ, dựa trên sự kiện và callback.
    Xử lý JSONThủ công (cần .json()).Tự động chuyển đổi.Thủ công (cần JSON.parse()).
    Xử lý lỗiChỉ từ chối Promise khi có lỗi mạng. Lỗi HTTP (404, 500) vẫn được coi là thành công.Từ chối Promise với cả lỗi mạng và lỗi HTTP.Xử lý qua onerror và kiểm tra status.
    Hủy RequestCần AbortController.cancelToken hoặc AbortController.Có phương thức abort().
    Tích hợp🚀 Tích hợp sẵn trong trình duyệt.📦 Cần cài đặt thư viện bên ngoài.Tích hợp sẵn trong trình duyệt.

    Khi nào nên dùng Fetch? Tuyệt vời cho các dự án không yêu cầu phức tạp, muốn tận dụng API gốc của trình duyệt mà không cần thêm thư viện.

    Khi nào nên dùng Axios? Lựa chọn hàng đầu cho các ứng dụng lớn, cần các tính năng nâng cao như interceptors (can thiệp vào request/response), xử lý lỗi tốt hơn, tự động chuyển đổi JSON và timeout.

    Những lưu ý quan trọng khi dùng Fetch là gì?

    Những lưu ý quan trọng khi dùng Fetch là gì
    Những lưu ý quan trọng khi dùng Fetch là gì
    1. Xử lý lỗi HTTP: fetch() chỉ thất bại (reject a promise) khi có lỗi liên quan đến mạng (mất kết nối). Nó sẽ không thất bại nếu nhận được mã lỗi HTTP như 404 (Not Found) hay 500 (Internal Server Error). Bạn phải tự kiểm tra response.ok hoặc response.status để xử lý các trường hợp này.
    2. Gửi Cookies: Mặc định, fetch() không gửi hoặc nhận cookies từ server. Để bật tính năng này, bạn cần thêm tùy chọn: credentials: 'include'.
    3. Hủy yêu cầu: Để hủy một yêu cầu fetch đang chờ, bạn cần sử dụng một đối tượng AbortController.

    Kết luận

    Fetch API là một công cụ cực kỳ mạnh mẽ và là tiêu chuẩn hiện đại cho việc thực hiện các yêu cầu mạng trong JavaScript. Với cú pháp đơn giản, dựa trên Promise và được tích hợp sẵn, nó là kỹ năng bắt buộc phải có đối với bất kỳ nhà phát triển web nào. Hiểu rõ cách hoạt động và những lưu ý của nó sẽ giúp bạn xây dựng các ứng dụng web hiệu quả và chuyên nghiệp hơn.

    5/5 - (1 bình chọn)

    Công nghệ tương lai Lập trình/ Code

    Portainer Là Gì? Toàn Tập Về Công Cụ Quản Trị Container Hàng Đầu (Hướng Dẫn Chi Tiết)

    Sự bùng nổ của công nghệ Container hóa (Containerization) với đầu tàu là Docker

    Xem thêm

    Công nghệ tương lai Công cụ và hướng dẫn Lập trình/ Code

    Helper Là Gì? Bí Quyết Viết Code “Sạch” Và Tối Ưu Trong Lập Trình

    Trong thế giới lập trình và phát triển phần mềm, việc phải lặp đi

    Xem thêm

    Digital Maketing Đồ Họa và Video Xu hướng

    Des là gì? Giải mã ý nghĩa của Des trong Thiết kế, SEO, IT & Logistics

    Bạn đang lướt mạng xã hội và thấy ai đó bình luận: “Dân Des

    Xem thêm

    Để lại một bình luận

    Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *

    Chào mừng bạn đến với TASDIGITAL.net
    Chào mừng bạn đến với TASDIGITAL.net