FileReaderSync
I have been working on updating the FileReader.js JavaScript file reading library lately to help out with a few different projects. This library has provided a quick way to get started with reading files on a few different projects, like mothereffinganimatedgif.com and Instant Sprite.
One thing I noticed was that there is a FileReaderSync API, meant for loading files synchronously.
You might wonder why on earth would you want to load a file synchronously in your browser - that seems like it could block the entire UI until the file is loaded! It turns out you can't, at least not in the normal window
context. FileReaderSync only exists inside of the context of a WebWorker:
Implementation
View a A working JS Fiddle using FileReaderSync{.btn}.
I also wrote about how to load web workers without a JavaScript file, but this technique works just fine using a normal external reference.
markup
<input type='file' id='files' multiple onchange='handleFileSelect()' />
page javascript
function processFiles(files, cb) {
var syncWorker = new Worker('worker.js');
syncWorker.onmessage = function(e) {
cb(e.data.result);
};
Array.prototype.forEach.call(files, function(file) {
syncWorker.postMessage(file);
});
}
function handleFileSelect() {
var files = document.getElementById('files').files;
processFiles(files, function(src) {
var img = new Image();
img.src = src;
document.body.appendChild(img);
});
}
worker.js
self.addEventListener('message', function(e) {
var data=e.data;
try {
var reader = new FileReaderSync();
postMessage({
result: reader.readAsDataURL(data)
});
} catch(e){
postMessage({
result:'error'
});
}
}, false);
The jsFiddle demo is a little more complicated than this, since it handles checking for support and an inline worker.
Gotchas
Something that was a little weird is that since you can't detect support from the main window, I need to spawn off a worker to post the message of whether it supports FileReaderSync. See a jsFiddle to detect FileReaderSync support. There may be a better way to do this, but I don't know of it.
This can be pretty complicated, but I have been tying it all into the filereader.js plugin, to make reading with FileReaderSync
just an option along with the standard FileReader
Performance
It's hard for me to accurately measure the performance. On one hand, the FileReaderSync seems to load the images in a slower time per image (measured in milliseconds). I assume that this is due to the overhead and message passing with the worker, or possibly because it is a newer implementation.
However, on large images and videos, it definitely feels like the UI does not lock up as much when processing the files.
Purpose
I feel like maybe part of the point of this API is when you want to some heavy lifting with the file after it is loaded but still inside the worker, which isn't currently supported in FileReader.js. I could imagine ways this use case could be supported though (maybe by passing in a process()
function as a string that the worker could call?
Check out the FileReader.js demo and see if you can tell a difference! I'd love to get any kinks worked out and get some feedback - I have been thinking of setting up a js-file-boilerplate project on Github to tie together a bunch of this functionality in a sample project.