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

When uploading large assets like documents, videos, or raw datasets, providing visual feedback with an accurate progress bar is essential for user experience. While the modern Fetch API does not expose upload progress events, XMLHttpRequest (XHR) and the browser Streams API provide full control.

Why Fetch API Lacks Upload Progress

The Fetch API was designed around WHATWG Streams. While streaming request bodies are becoming supported in some modern browsers, fetch() still does not offer a standardized onUploadProgress callback.

To track upload bytes sent over the wire, XMLHttpRequest remains the industry standard.

Verified Test Asset.docx

Need a large file to test smooth progress animation? Download our 50MB DOCX test file.

Tải File Mẫu 50MB DOCX →

Building an Upload Progress Bar Component

Here is a complete, clean implementation using modern TypeScript and Tailwind CSS:

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();

    // Listen to upload progress events
    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('Network error during upload')));
    xhr.addEventListener('abort', () => reject(new Error('Upload aborted by user')));

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

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

Styling with Tailwind CSS and CSS Transitions

Smooth animations prevent the progress bar from jumping erratically:

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>

Practical Tips

  • Compute transfer speed: Measure event.loaded - lastLoaded every second to display dynamic upload speed in MB/s and estimated time remaining (ETA).
  • Handle artificial pauses: Browsers fire the final 100% event once all bytes leave the client socket, but the server may take several additional seconds to scan or persist the file before sending the HTTP 200 response. Indicate a "Processing..." state between 100% and response arrival.
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