I'm using FileReader to display local images in a Backbone application. Smaller images are displayed immediately without any issues, but when the images are several megabytes or larger, it takes Chrome 2 or 3 seconds to load the image (on a brand new MacBook Pro with 8 GB RAM).
As pointed out in the comments, large images load instantaneously in this File API tutorial, so the issue is not with FileReader
but rather with my particular implementation in Backbone.
I've included the relevant Backbone model and view below. Here's an outline of the logic:
FileReader
into which the file path is passed.Image
is created and the src
of the Image
is set to the data URL provided by the FileReader
.initialized
attribute of the model is set to true
(thus firing a change
event on the model).change
event on the model, the render
function is called, which replaces the background image of a div
with the data URL.Backbone Model
var PhotoModel = Backbone.Model.extend({
initialize: function() {
this.set({"available": true});
this.initialized = false;
if (this.get("file")) {
this.uploadPhoto();
}
},
uploadPhoto: function() {
var file = this.get("file");
var reader = new FileReader();
var model = this;
reader.onload = function(event) {
var image = new Image();
image.onload = function() {
model.set({width: this.width, height: this.height});
model.set("initialized", true);
};
image.src = event.target.result;
model.set("dataURL", event.target.result);
}
reader.readAsDataURL(file);
},
});
Backbone View
var PhotoFormView = Backbone.View.extend({
className: "photo-form",
initialize: function() {
this.listenTo(this.model, "change", this.render);
this.render();
},
render: function() {
$(this.el).find(".photo").css({"background-image": "url(" + this.model.get("dataURL") + ")"});
},
});
Below is a screenshot of the Chrome timeline. The largest delay seems to happen between the data URL request and the load event (this accounts for approximately 0.5 seconds). I'm not sure what "Recalculate style" is all about. I'm also not sure why there are so many paint events (it appears to be rendering in the scrollbar area).
SOLUTION
I had assumed that the browser would be able to natively resize images more efficiently than any JavaScript solution, but this assumption was wrong. By resizing the images before they are displayed, I was able to reduce the delay to about 50 milliseconds. I used an open source plugin called JavaScript Load Image to handle the image loading and resizing (it uses the HTML5 canvas
tag). Here's my modified Backbone model:
var PhotoModel = Backbone.Model.extend({
initialize: function() {
this.set({available: true});
this.set({initialized: false});
if (this.get("file")) {
this.uploadPhoto();
}
},
uploadPhoto: function() {
var model = this;
loadImage(this.get("file"), function (img) {
model.set({img: img});
model.set({initialized: true});
}, {maxHeight: 344});
},
});
A large volume of unoptimized images is usually the most common reason behind website slowness. High-resolution images can consume lots of bandwidth while loading. Uploading larger sized images and then scaling them down can unnecessarily increase the size of your web page – causing your website to load slowly.
Possible causes. The web page is not pointing to the correct URL (location) of the image. The server or computer hosting the image has moved or removed the image, and the web page has not yet been updated. The web page or computer hosting the image is getting too many requests and can't send you the image.
I was encountering the same problem when loading large images using FileReader. If you're not planning on displaying them at full size, it seems the workaround involves scaling the image before displaying it using a canvas
element.
After mixed success with my own implementation, I opted to use JavaScript Load Image (MIT license) and its maxWidth
option, which solved this and more (unforseen) problems.
Try the the demo and see if your images load nicely.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With