FileDummy Logo
FileDummy
Tải Lên & Xử Lý Tệp Tin

Tạo Thanh Tiến Trình Upload File: Hướng Dẫn Chi Tiết HTML5 + Fetch API

Xây dựng thanh tiến trình tải file theo thời gian thực sử dụng HTML5 và XMLHttpRequest. Đi kèm CSS mượt mà và file mẫu 50MB DOCX để kiểm thử.

17 tháng 9, 20269 phút đọc1,420 lượt xem
javascripthtml5xhrprogress-barfrontend

Khi tải lên các tài sản lớn như tài liệu, video hoặc tập dữ liệu thô, cung cấp phản hồi trực quan bằng thanh tiến trình chính xác là điều thiết yếu cho trải nghiệm người dùng. Mặc dù Fetch API hiện đại không hiển thị sự kiện tiến trình tải lên, XMLHttpRequest (XHR) và Streams API của trình duyệt cung cấp khả năng kiểm soát đầy đủ.

Tại Sao Fetch API Thiếu Tiến Trình Tải Lên

Fetch API được thiết kế xung quanh WHATWG Streams. Mặc dù streaming request body ngày càng được hỗ trợ trong một số trình duyệt hiện đại, fetch() vẫn không cung cấp callback onUploadProgress chuẩn hóa.

Để theo dõi số byte gửi đi qua mạng, XMLHttpRequest vẫn là tiêu chuẩn ngành.

Thử Nghiệm Thực Tế.docx

Cần file lớn để kiểm thử animation tiến trình mượt mà? Tải file DOCX test 50MB của chúng tôi.

Tải File Mẫu 50MB DOCX →

Xây Dựng Component Thanh Tiến Trình Tải Lên

Dưới đây là triển khai hoàn chỉnh, sạch sẽ bằng TypeScript hiện đại:

TypeScript
export function uploadWithProgress(
  file: File,
  url: string,
  onProgress: (percent: number, loaded: number, total: number) => void
): Promise<string> {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();

    // Lắng nghe sự kiện tiến trình tải lên
    xhr.upload.addEventListener('progress', (event) => {
      if (event.lengthComputable) {
        const percent = Math.round((event.loaded / event.total) * 100);
        onProgress(percent, event.loaded, event.total);
      }
    });

    xhr.addEventListener('load', () => {
      if (xhr.status >= 200 && xhr.status < 300) {
        resolve(xhr.responseText);
      } else {
        reject(new Error(`HTTP ${xhr.status}: ${xhr.statusText}`));
      }
    });

    xhr.addEventListener('error', () => reject(new Error('Lỗi mạng trong quá trình tải lên')));
    xhr.addEventListener('abort', () => reject(new Error('Tải lên bị hủy bởi người dùng')));

    const formData = new FormData();
    formData.append('file', file);

    xhr.open('POST', url, true);
    xhr.send(formData);
  });
}

Tạo Kiểu Với CSS Transitions

Animation mượt mà ngăn thanh tiến trình nhảy giật cục:

HTML
<div class="w-full bg-slate-800 rounded-full h-3 overflow-hidden p-0.5">
  <div
    id="progress-bar"
    class="bg-gradient-to-r from-blue-500 to-indigo-600 h-full rounded-full transition-all duration-200 ease-out"
    style="width: 0%"
  ></div>
</div>

Các Mẹo Thực Tiễn

  • Tính toán tốc độ truyền: Đo event.loaded - lastLoaded mỗi giây để hiển thị tốc độ tải lên động bằng MB/s và thời gian dự kiến còn lại (ETA).
  • Xử lý tạm dừng nhân tạo: Trình duyệt kích hoạt sự kiện 100% cuối cùng khi tất cả byte rời khỏi socket client, nhưng máy chủ có thể mất thêm vài giây để quét hoặc lưu tệp trước khi gửi HTTP 200. Hiển thị trạng thái "Đang xử lý..." giữa 100% và khi nhận được response.
NDL

Nguyễn Đại Long

Tác Giả

Backend Lead • Chuyên gia Kiến trúc Hệ thống Phân tán & Lưu trữ Đám mây

Hơn 4 năm kinh nghiệm thiết kế các hệ thống xử lý tệp tải lên thông lượng lớn, tối ưu hóa cơ sở dữ liệu và hạ tầng phân tán Cloudflare R2 / AWS S3. Người sáng lập FileDummy và Mạng lưới Hệ sinh thái NDL.

Bài viết này có hữu ích không?

Bấm Thích để ủng hộ tác giả và giúp bài viết lan tỏa tới cộng đồng lập trình viên.

Thảo Luận Kỹ Thuật & Đóng Góp Ý Kiến (0)

Chia sẻ kết quả benchmark, phản hồi các trường hợp biên hoặc đặt câu hỏi chuyên môn.

0/3000

Chưa có bình luận nào. Hãy là lập trình viên đầu tiên bắt đầu cuộc thảo luận!

Câu Hỏi Thường Gặp (FAQ)

Why doesn't the Fetch API support upload progress natively?▾

The Fetch API does not expose upload progress events. For upload progress, use XMLHttpRequest with the xhr.upload.onprogress event. Download progress is available via the Streams API on the response body.

How do I show download progress with the Fetch API?▾

Use response.body.getReader() and track bytes read versus Content-Length. This works natively in all modern browsers without XHR.

What is a realistic file size for testing an upload progress bar?▾

A 50MB file takes 8–40 seconds on typical broadband — long enough to observe a meaningful progress animation. Use FileDummy's 50MB DOCX sample as an ideal test file.

Bài Viết Liên Quan