Show progress of download with remaining time – Javascript
Convert time to different timezones
Learn how to show progress of download with remaining time in Javascript. We will be creating a simple bootstrap progress bar.
There are multiple ways to download a file from some website. The easiest way is to simply put an anchor tag with a text “Download”. And give the download attribute. Set the hypertext reference to the file which needs to be download. When the user clicks on it, the file will be downloaded using default browser download manager or via IDM.
However, there are some scenarios where that technique will not help. Take an example of a file with a very large size i.e. 1GB or greater, or a user running on a slow internet connection. The chances are the file may get interrupted during the download. In this case, user might have to re-download the file again. Even if he is using IDM, if the link gets expired then IDM will not resume the file. Instead it will download the file again from start.
Download file inside the browser
The second approach is to download the file inside the browser, show progress of download using a progress bar to the user. When the file is completely downloaded, then show a button which when clicked, will save the file in the selected destination on his computer. In this way, the file will be saved in the computer in just a couple of seconds. Because the file was already been downloaded inside the browser.
There are many other reasons for implementing this technique. For example, you can show advertisements to users until the file gets downloaded. This will help you monetize your website as well.
Get file from server
First we are going to get the file from the server and make it available for download. So, create a button that when clicked when send an AJAX request and get the file from the server. Also, an anchor tag must be created which will give the hypertext reference to the file when completely download in the browser. Lastly, we will add a progress bar which will show the progress of download.
<button id="download-button">Download</button>
<a id="save-file">Save File</a>
<progress id="progress" value="0"></progress>
Now in javascript, first we attach an onclick listener to the button. And call an AJAX request to the file which needs to be downloaded.
<script>
var fileName = "Archive.zip";
document.querySelector('#download-button')
.addEventListener('click', function() {
request = new XMLHttpRequest();
request.responseType = 'blob';
request.open('get', fileName, true);
request.send();
request.onreadystatechange = function() {
if(this.readyState == 4 && this.status == 200) {
var obj = window.URL.createObjectURL(this.response);
document.getElementById('save-file').setAttribute('href', obj);
document.getElementById('save-file').setAttribute('download', fileName);
setTimeout(function() {
window.URL.revokeObjectURL(obj);
}, 60 * 1000);
}
};
});
</script>
First we are creating an AJAX object. Note that the response type must be “blob”. By default, AJAX response type is text but since we wanted the download-able file to be returned from AJAX so we must set the response type to “blob”. In open function, first set the method of ajax which will be GET, then the second parameter should be the complete path of file which needs to be downloaded. We have created a variable where you can place your dynamic value. The first parameter will tell that the request must be asynchronous.
send() in AJAX
send() function will send the request to download the file and onreadystatechange will be called multiple times whenever the state of request changes. For example, when the request sent, when the request received and when the response is sent from the server. Here the readyState having value 4 and status having value 200 indicates the completion of request.
When the response is successfully received, we know that the response will be a downloadable file. Basically it will return the URL from where the user can save the file in his computer. So we will create an object using that URL, we will be using Javascript built-in URL object and call the function createObjectURL and pass the response received from ajax. Note that this response is not a responseText variable which is a string.
When the object is created using that URL, we will simply assign that as hypertext reference to our anchor tag. We are also setting the download attribute to anchor tag which tells the browser that the hypertext link to this anchor tag should be made downloadable.
revokeObjectURL
Since the object is created inside the browser, so it is also occupying some space. We can free it’s allocated resources after a few seconds. For example, the average size of file is 1GB and the user downloads 6 or 7 files, but if you do not free the object resources, then it might end up taking a lot of space in memory of your browser. So we are freeing the resources after 60 seconds, and we need to call the revokeObjectURL function and pass the object variable in it.
Display download progress
Now we need to create a progress bar and a text which will show the download percentage in textual format. In the above step, you can see that we have already created a progress tag, now we also need to create a span tag which shows the progress in percentage.
<span id="progress-text"></span>
<script>
var progress = document.getElementById("progress");
var progressText = document.getElementById("progress-text");
request.onprogress = function(e) {
progress.max = e.total;
progress.value = e.loaded;
var percent_complete = (e.loaded / e.total) * 100;
percent_complete = Math.floor(percent_complete);
progressText.innerHTML = percent_complete + "%";
};
</script>
In javascript, first we are getting both nodes (progress & span) in separate variables. AJAX also provides us a method to track progress in an event called onprogress, it will have an argument and it tells the total amount of data that needs to be transferred (the size of file) and the which is currently been transferred so far.
We will set the total amount of data as the maximum value for the progress bar. And it continually changes the value of progress bar to the amount of data being transferred. So you will see the progress bar gradually moves from left to right as the file gets downloaded. The speed of progress bar depends on the size of the file and your internet connection.
File download percentage
So the progress bar has been set, now we display the percentage of the file downloaded in numbers. As we have already created a span tag in HTML and a variable for it in javascript. So we just need to calculate the percentage and display in span tag. We can calculate the percentage of the file downloaded by dividing the file currently downloaded by total size of file. That will return the value in between 0 and 1, for example 0.841. Multiplying this by 100 will return in 84.1 which means that 84.1 percent file has been downloaded.
If you do not want to display the decimal points with it, you can call the floor method and it will return the integer value. Then we simply set this percentage in span tag and add the percentage sign with it too.
Display transfer rate
At this point, if you were downloading that file via IDM or browsers default download manager, you will be able to view the downloading speed of your file. So our next step is to show downloading speed too. Create a simple span tag and get it in javascript as we did earlier. To get the downloading speed, we have to apply some math on it.
<span id="download-progress-text"></span>
<script>
var downloadProgressText = document.getElementById("download-progress-text");
document.querySelector('#download-button')
.addEventListener('click', function() {
var startTime = new Date().getTime();
//// previous code in download button click listener
});
request.onprogress = function(e) {
var duration = ( new Date().getTime() - startTime ) / 1000;
var bps = e.loaded / duration;
var kbps = bps / 1024;
kbps = Math.floor(kbps);
downloadProgressText.innerHTML = kbps + " KB / s";
};
</script>
Getting the download speed means we need to know how much KB of data is transferred in one second. Since we are getting downloaded data in bytes so we can convert that in kilo bytes by simply dividing by 1024. First we will get the duration since the file started downloading till now. We can get it by getting the difference between current time and start time. That will return the time in milliseconds, so we can convert that into seconds by dividing with 1000.
When we get the total duration of AJAX then we can get the bytes transferred per second by dividing the data currently transferred by this duration. Now we have the Bytes per second, we can simply convert that to KB by dividing with 1024. Since there are 1024 bytes in one KB. This value may also be in decimal points, so we will convert that into integer too by using the same Math.floor() function. Lastly, we have set this variable in span tag and also display KB/s as string in it.
Get remaining time of download
The algorithm to calculate the remaining time is pretty simple. We get the difference between total size of file and the file currently being downloaded, and divide that by amount of data downloaded in bytes per second. This gives the time in seconds. But we need to show it in minutes too. For example, if this returns 90 seconds, then we need to display it as 1 minute and 30 seconds.
request.onprogress = function(e) {
...
var time = (e.total - e.loaded) / bps;
var seconds = time % 60;
var minutes = time / 60;
seconds = Math.floor(seconds);
minutes = Math.floor(minutes);
progress.setAttribute("aria-valuemax", e.total);
progress.setAttribute("aria-valuenow", e.loaded);
progress.style.width = percent_complete + "%";
progress.innerHTML = percent_complete + "%";
downloadProgressText.innerHTML = kbps + " KB / s" + "<br>" + minutes + " min " + seconds + " sec remaining";
};
No need to create another span tag for it, we will display this data inside span we created for displaying transfer rate. We use the modulus operator to get the remaining seconds, and we apply that to 60 since there are 60 seconds in 1 minute. Similarly, we can divide the time to 60 and it returns the time in minutes since 60 seconds composed of 1 minute.
These seconds and minutes may also be in decimal points, so we convert them to an integer using Math.floor() function as above. Lastly, we are appending that along with KB/s and prepending a line break (<br>) for readability.
Abort ajax request
We can abort any AJAX request using simple abort() function from ajax object. So we are simply creating a button which when clicked will abort the ajax request and you will see that progress of download, text, seconds and minutes will be stopped.
<button onclick="request.abort();" type="button">Abort</button>
Conclusion
This tutorial does not include any external library like jQuery. So you should be able to apply this in your project without having to include any library. It only contains Vanilla JS.
Though we could have use the NetworkInformation API to check transfer rate but it does not support all browsers at the time of writing this. So we do not want you to implement this in your website. Then later find out that your users are having problem downloading the file 🙂
We have tried to create this tutorial as simple and accurate as we can. But if you still find any problem on our side, please do not hesitate to get in touch with us.
[wpdm_package id=’209′]
How the file will automatically download after completing 100% rather than clicking on save the file
You can use the following code in your “request.onprogress” event:
if (percent_complete >= 100) {
document.getElementById(‘save-file’).click();
}
Below is the script i use to share files on my browser.
How can i display the download progress Once The “shareButton” is clicked and the blob starts downloading in the browser ?
const shareDialog = document.querySelector(‘.share-dialog’);
const shareButton = document.getElementById(“shareButton”);
const urlToFile = async (url) => {
const response = await fetch(url);
const blob = await response.blob();
const file = new File([blob], “video.mp4”, { type: blob.type });
return file;
};
shareButton.addEventListener(“click”, async () => {
if (window.navigator.share) {
const file = await urlToFile(
“https://berkine-upload-share.s3.eu-west-1.amazonaws.com/Mosquito.mp4”
);
const files = [file];
if (!navigator.canShare || !navigator.canShare({ files: files })) {
alert(“Unsupported share feature”);
return;
}
navigator
.share({
files: files,
title: “Sweet Shiba Inu”,
url: ‘https://abc.com’
})
.then(() => console.log(“Share was successful.”))
.catch((error) => console.log(“Sharing failed”, error));
} else {
shareDialog.classList.add(‘is-open’);
}
});
Below is the script i use to share files on my browser.
How can i display the download progress Once The “shareButton” is clicked and the blob starts downloading in the browser ?
https://codepen.io/fdkay/pen/BadMamx
Sorry! File not found!
can you reupload please , i’m learning 😀
Thanks for reporting. Let me re-upload.
It has been re-uploaded. Kindly refresh the page and try again.