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.

Đ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ọiopen()rồisend(). - 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.
- 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 (
- 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ápasync/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
RequestvàResponseđượ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.
- Promise-based: Đây là thay đổi cốt lõi. Mọi thứ trong Fetch đều xoay quanh
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.
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ượngHeaders.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.
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àtruenếustatusnằm trong khoảng 200-299, vàfalsenế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ượngHeaderschứa các header của phản hồi.body: Đây là mộtReadableStream(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ũ:

- ✅ 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ụ)

1. Cú pháp cơ bản
Cú pháp của fetch() rất đơn giản:
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,fetchsẽ mặc định thực hiện một yêu cầuGET.
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.
// 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.
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.
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.
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ì?

- 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 traresponse.okhoặcresponse.statusđể xử lý các trường hợp này. - 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'. - 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ượngAbortController.
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.

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êmTh3
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êmTh3
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êmTh3