Responding to HTML5 FileReader Events

By Rob Gravelle

You may recall the recent Drag Files into the Browser from the Desktop with HTML5 article, which demonstrated how to use HTML5 Drag & Drop and HTML5 FileReader to accept image files from the Desktop and display them in the browser. The key to getting that to work was understanding the implications of the asynchronous nature of FileReader events. In today's follow up article, we're going to delve even deeper into the FileReader's events by adding more detailed progress reports as well as some error handling.

Including Progress Information

My Determine an Image's Type using the JavaScript FileReader article featured individual progress bars for each image load operation. Here too we can display progress information by listening to the FileReader's onprogress event. This time, instead of a progress bar, I thought that it might be interesting to display a text message that includes the percentage completed and the file name. The interesting part is that accessing the file name requires binding the property to the event handler, just as we bound the file object to the reader's onloadend event in the "Drag Files into the Browser from the Desktop" article. Here's the code for the onprogress event handler:


for (var i=0; i<files.length; i++) {

  var file = files[i];

  var reader = new FileReader();


  addEventHandler(reader, 'loadend', function(e, file) { 

    //function code



  addEventHandler(reader, 'progress', function(e, fileName) { 

    if (e.lengthComputable) {

      var percentage = Math.round((e.loaded * 100) /;

      status.innerHTML = 'Loaded : '+percentage+'%'+' of '+fileName;






Note that the file name is always the second argument because bindToEventHandler() passes the event object as the first argument

The New-and-improved bindToEventHandler() Method

Calling bindToEventHandler() for the onprogress event uncovered an issue with the existing code. While it worked perfectly well with one-time events such as the FileReader's onloadend event, it did not process the progress event object correctly when called numerous times. The reason is that the closure caused the previous event state to be retained in the parameter array. Consequently, every call to the event handler added the latest event object to the start of the array. It's actually a great way to retain an object's history, but that's not what we're after here; the latest and greatest progress update is all we need. The solution is as simple as unshifting the progress event element to the boundParameters array outside of the closure and then updating the first boundParameters element within the returned function:

Function.prototype.bindToEventHandler = function bindToEventHandler() {

  var handler         = this;

  var boundParameters =;

      boundParameters.unshift(''); //unshift requires an argument


  //create closure

  return function(e) {

      e = e || window.event; // get window.event if e argument missing (in IE)  

      boundParameters[0] = e; //update event info


      handler.apply(this, boundParameters);



Here's some sample progress event output in the Firefox log:

Loaded : 25% of Raw Sugar 2009.JPG

Loaded : 27% of Trapped in Conway!.JPG

Loaded : 27% of Trapped in Conway! 2.JPG

Loaded : 24% of Nien Nunb.bmp

Loaded : 51% of Raw Sugar 2009.JPG

Loaded : 53% of Trapped in Conway!.JPG

Loaded : 55% of Trapped in Conway! 2.JPG

Loaded : 48% of Nien Nunb.bmp

Loaded : 76% of Raw Sugar 2009.JPG

Loaded : 80% of Trapped in Conway!.JPG

Loaded : 82% of Trapped in Conway! 2.JPG

Loaded : 72% of Nien Nunb.bmp

Loaded : 96% of Nien Nunb.bmp

This is how a progress message appears in the browser:


The above progress messages are replaced by a onloadend one similar to the following once the image has finished loading:


Something Has Gone Horribly Wrong!

Well, not really, but it could! That's why you need to attach some error handling to the FileReader's onerror event. To make it easier to trap different kinds of errors, the error object of the onerror event contains a number of constants. They are:

  • NOT_FOUND_ERR (1): The file does not exist. A strange occurence considering that the user presumably selected or dragged the file from the file system. Nonetheless, it's there if you need it, in the rare event that someone deletes the file between the time it is acquired and the time that the FileReader attempts to read it.
  • SECURITY_ERR (2): Security restrictions prevented the script from reading the file.
  • ABORT_ERR (3): The file read was aborted - typically when the user cancels.
  • NOT_READABLE_ERR (4): The file could not be read because of a change to permissions since the file was acquired - likely because the file was locked by another program.
  • ENCODING_ERR (5): The readAsDataURL() method failed because the file was too long to encode as a "data://" URL.


Here's some code that listens to the onerror event and displays a message to the user to relate what went wrong. This time, we have to check the window.event property because we aren't binding anything to this handler:

  addEventHandler(reader, 'progress', function(e, fileName) {

    //function code                                   



  addEventHandler(reader, 'error', function(e) {

    e = e || window.event; // get window.event if e argument missing (in IE)  

    switch( {


        status.innerHTML = 'File not found!';



        status.innerHTML = 'File not readable!';



        status.innerHTML = 'Read operation was aborted!';



        status.innerHTML = 'File is in a locked state!';



        status.innerHTML = 'The file is too long to encode in a "data://" URL.';



        status.innerHTML = 'Read error.';






Here is the demo file for today's article.

A Word about Accessibility

Always keep in mind that, while drag & drop can make loading files from the desktop easier, there are users who can only use the keyboard. For that reason, drag & drop should always enhance the file input control and not replace it, so that users who can't perform a mouse drag & drop operation can still complete the task.


If you enjoyed this article, please contribute to Rob's less lucrative music career by purchasing one of Rob's cover or original songs from for only 0.99 cents each.

Rob Gravelle resides in Ottawa, Canada, and is the founder of Rob has built systems for Intelligence-related organizations such as Canada Border Services, CSIS as well as for numerous commercial businesses. Email Rob to receive a free estimate on your software project. Should you hire Rob and his firm, you'll receive 15% off for mentioning that you heard about it here!


In his spare time, Rob has become an accomplished guitar player, and has released several CDs. His former band, Ivory Knight, was rated as one Canada's top hard rock and metal groups by Brave Words magazine (issue #92).

Rob uses and recommends MochaHost, which provides Web Hosting at $3.10 per month, 2 LifeTime Free Domains, and 6 Months Free!

And here’s the source for the “File Upload and Display Demo.html” file: A File Upload and Display Demo

A File Upload and Display Demo

Drag the files from a folder to a selected area ...
Drop files here.

Make a Comment

Loading Comments...

  • Web Development Newsletter Signup

    Invalid email
    You have successfuly registered to our newsletter.
Thanks for your registration, follow us on our social networks to keep up-to-date