The JavaScript ProgressEvent
Object: Monitoring Resource Loading
The ProgressEvent
object in JavaScript provides detailed information about the progress of an ongoing operation, such as loading a resource (e.g., image, script, or data file) or uploading data (e.g., submitting a form). This object is particularly useful when working with XMLHttpRequest
(XHR), fetch
API, and other resource loading mechanisms. Understanding ProgressEvent
allows developers to provide meaningful feedback to users about the status of these operations.
Purpose of the ProgressEvent
Object
The primary purpose of the ProgressEvent
object is to:
- Track the progress of resource loading or data transfer operations.
- Provide information about the amount of data loaded or transferred.
- Indicate whether the total size of the resource is known.
- Signal the completion or abortion of the operation.
Syntax
A ProgressEvent
is created automatically by the browser when a progress-related event occurs. You typically don’t create it directly but access it via event listeners attached to the target element (e.g., XMLHttpRequest
, HTMLMediaElement
).
target.addEventListener("progress", function (event) {
// Access ProgressEvent properties here
});
Where target
is the element dispatching the progress event.
Properties of the ProgressEvent
Object
The ProgressEvent
object has several properties that provide information about the progress of the operation:
Property | Type | Description |
---|---|---|
`lengthComputable` | Boolean | Indicates whether the total size of the resource being loaded or transferred is known. If `true`, the `total` property contains a meaningful value. |
`loaded` | Number | The amount of data loaded or transferred so far, in bytes. |
`total` | Number | The total size of the resource being loaded or transferred, in bytes. Meaningful only if `lengthComputable` is `true`. |
`target` | Object | The element to which the listener is attached (e.g., XMLHttpRequest object). |
`type` | String | The type of event (e.g., “progress”, “loadstart”, “load”, “error”, “abort”). |
Types of Progress Events
Several events use the ProgressEvent
object:
loadstart
: Dispatched when the loading process starts.progress
: Dispatched periodically as data is being loaded or transferred.load
: Dispatched when the loading process is complete and successful.error
: Dispatched when an error occurs during the loading process.abort
: Dispatched when the loading process is aborted.timeout
: Dispatched when the loading process times out.loadend
: Dispatched when the loading process completes, regardless of whether it was successful or not.
Examples of Using ProgressEvent
Let’s explore how to use the ProgressEvent
object in different scenarios, from basic resource loading to more complex file uploads.
Monitoring Image Loading Progress
This example demonstrates how to monitor the loading progress of an image and display a progress bar.
<div id="imageProgressContainer">
<img id="imageToLoad" src="" alt="Loading Image" style="display: none" />
<div id="imageProgressBar">
<div id="imageProgress"></div>
</div>
<p id="imageProgressText">Loading: 0%</p>
</div>
<style>
#imageProgressBar {
width: 200px;
height: 20px;
background-color: #eee;
border: 1px solid #ccc;
}
#imageProgress {
width: 0%;
height: 100%;
background-color: #4caf50;
}
</style>
<script>
const imageToLoad_img = document.getElementById("imageToLoad");
const imageProgressBar_img = document.getElementById("imageProgressBar");
const imageProgress_img = document.getElementById("imageProgress");
const imageProgressText_img = document.getElementById("imageProgressText");
imageToLoad_img.addEventListener("loadstart", function () {
imageProgressText_img.textContent = "Loading started...";
});
imageToLoad_img.addEventListener("progress", function (event) {
if (event.lengthComputable) {
const percentComplete = (event.loaded / event.total) * 100;
imageProgress_img.style.width = percentComplete + "%";
imageProgressText_img.textContent =
"Loading: " + percentComplete.toFixed(2) + "%";
} else {
imageProgressText_img.textContent = "Loading...";
}
});
imageToLoad_img.addEventListener("load", function () {
imageProgressText_img.textContent = "Loading complete!";
});
imageToLoad_img.addEventListener("error", function () {
imageProgressText_img.textContent = "Loading failed.";
});
imageToLoad_img.src = "https://dummyimage.com/600x400/4caf50/fff"; // Replace with your image URL
</script>
This example demonstrates how to use the loadstart
, progress
, load
, and error
events to provide feedback on the image loading process.
Monitoring File Upload Progress with XMLHttpRequest
This example demonstrates how to monitor the progress of a file upload using XMLHttpRequest
and the upload
property.
<input type="file" id="fileInput" />
<button id="uploadButton">Upload</button>
<div id="uploadProgressBar">
<div id="uploadProgress"></div>
</div>
<p id="uploadProgressText">Upload: 0%</p>
<style>
#uploadProgressBar {
width: 300px;
height: 20px;
background-color: #eee;
border: 1px solid #ccc;
}
#uploadProgress {
width: 0%;
height: 100%;
background-color: #2196f3;
}
</style>
<script>
const fileInput_xhr = document.getElementById("fileInput");
const uploadButton_xhr = document.getElementById("uploadButton");
const uploadProgressBar_xhr = document.getElementById("uploadProgressBar");
const uploadProgress_xhr = document.getElementById("uploadProgress");
const uploadProgressText_xhr = document.getElementById("uploadProgressText");
uploadButton_xhr.addEventListener("click", function () {
const file_xhr = fileInput_xhr.files[0];
if (file_xhr) {
const xhr = new XMLHttpRequest();
const formData = new FormData();
formData.append("file", file_xhr);
xhr.upload.addEventListener("loadstart", function () {
uploadProgressText_xhr.textContent = "Upload started...";
});
xhr.upload.addEventListener("progress", function (event) {
if (event.lengthComputable) {
const percentComplete = (event.loaded / event.total) * 100;
uploadProgress_xhr.style.width = percentComplete + "%";
uploadProgressText_xhr.textContent =
"Upload: " + percentComplete.toFixed(2) + "%";
} else {
uploadProgressText_xhr.textContent = "Upload in progress...";
}
});
xhr.addEventListener("load", function () {
uploadProgressText_xhr.textContent = "Upload complete!";
});
xhr.addEventListener("error", function () {
uploadProgressText_xhr.textContent = "Upload failed.";
});
xhr.open("POST", "/upload", true); // Replace with your upload URL
xhr.send(formData);
} else {
uploadProgressText_xhr.textContent = "Please select a file.";
}
});
</script>
This example uses the XMLHttpRequest
object to upload a file and monitors the upload progress using the upload
property’s progress
event.
Note: The /upload
endpoint in the xhr.open()
method is a placeholder. You need to replace it with an actual server-side endpoint that handles file uploads. ⚠️
Monitoring Download Progress with fetch
API
While the fetch
API doesn’t directly provide progress events like XMLHttpRequest
, you can still monitor download progress by reading the response body as a stream and tracking the amount of data received.
<button id="downloadButton">Download File</button>
<div id="downloadProgressBar">
<div id="downloadProgress"></div>
</div>
<p id="downloadProgressText">Download: 0%</p>
<style>
#downloadProgressBar {
width: 300px;
height: 20px;
background-color: #eee;
border: 1px solid #ccc;
}
#downloadProgress {
width: 0%;
height: 100%;
background-color: #9c27b0;
}
</style>
<script>
const downloadButton_fetch = document.getElementById("downloadButton");
const downloadProgressBar_fetch = document.getElementById(
"downloadProgressBar"
);
const downloadProgress_fetch = document.getElementById("downloadProgress");
const downloadProgressText_fetch = document.getElementById(
"downloadProgressText"
);
downloadButton_fetch.addEventListener("click", async function () {
const url = "https://dummyimage.com/1024x768/9c27b0/fff"; // Replace with your download URL
try {
const response = await fetch(url);
const contentLength = response.headers.get("content-length");
if (!contentLength) {
downloadProgressText_fetch.textContent =
"Content length not available.";
return;
}
const total = parseInt(contentLength, 10);
let loaded = 0;
const reader = response.body.getReader();
const stream = new ReadableStream({
start(controller) {
function push() {
reader.read().then(({ done, value }) => {
if (done) {
controller.close();
downloadProgressText_fetch.textContent = "Download complete!";
return;
}
loaded += value.length;
const percentComplete = (loaded / total) * 100;
downloadProgress_fetch.style.width = percentComplete + "%";
downloadProgressText_fetch.textContent =
"Download: " + percentComplete.toFixed(2) + "%";
controller.enqueue(value);
push();
});
}
push();
},
});
const blob = await new Response(stream).blob();
const downloadUrl = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = downloadUrl;
a.download = "downloaded-file"; // Set the desired file name
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(downloadUrl);
} catch (error) {
downloadProgressText_fetch.textContent = "Download failed: " + error;
}
});
</script>
This example uses the fetch
API to download a file and monitors the download progress by reading the response body as a stream. This is a more advanced technique but provides a way to track download progress with fetch
.
Note: Make sure the server sends the content-length
header in the response for this example to work correctly. 💡
Browser Support
The ProgressEvent
object is widely supported across modern browsers.
Conclusion
The ProgressEvent
object is a valuable tool for providing feedback to users during resource loading and data transfer operations. By monitoring progress events and updating the user interface accordingly, you can create a more engaging and user-friendly experience. Whether you are loading images, uploading files, or downloading data, the ProgressEvent
object can help you keep your users informed and engaged.