The FileReader API is event driven. You define custom behavior in its event handlers when it either succeeds or fails to read a file and then pass a File object to one of the methods, such as
readAsText The result of the method, if successful, can finally be retrieved in the
The FileReader methods work asynchronously but don't return a Promise. And attempting to retrieve the result immediately after calling a method will not work, as the
.onload event handler fires only after the FileReader has successfully finished reading the file and updates the FileReader's
.result property. This can make FileReader a bit of a pain to work with when integrating it with an application.
Wrapping it With a Promise
A solution to make FileReader more pleasant to work with is to wrap its result in a Promise. Here's an example:
This function returns a Promise of a string that will resolve or reject only after the firing of the
.onerror event handlers, respectively. If the Promise is rejected the FileReader will abort and, in this case, return a custom DOMException but you can
reject with whatever you like. One good alternative is the FileReader's
.error property, which will also be a DOMException.
A Simplified API with Async/Await
Wrapping the result of a FileReader in a Promise allows us to
await the result of our
readUploadedFileAsText function and expect a string. Here's an example
onchange handler we could pass to a
<input type="file /> element (Full example on CodePen)
The CodePen link above shows the above code doing manual DOM manipulation. Here's an example of using the same readUploadedFileAsText function with async/await in a React application.
For an example in a TypeScript and React application, look here. Though this particular code example is part of an application using Redux so there's a fair bit of indirection.