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ử.
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.
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:
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:
<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 - lastLoadedevery 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.
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.
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.