我正在使用FileReader在 Backbone 应用程序中显示本地图像。较小的图像会立即显示而没有任何问题,但是当图像为几兆字节或更大时,Chrome 需要 2 或 3 秒才能加载图像(在具有 8 GB RAM 的全新 MacBook Pro 上)。
正如评论中所指出的,大图像在这个文件 API 教程中瞬间加载,所以问题不FileReader
在于我在 Backbone 中的特定实现。
我在下面包含了相关的 Backbone 模型和视图。这是逻辑的概述:
- 该模型创建一个新
FileReader
的文件路径传递到其中。 - 加载文件后,将
Image
创建 an 并将 的src
设置Image
为由FileReader
. - 加载图像后,模型会更新为图像的宽度和高度(在应用程序的其他地方使用),并且
initialized
模型的属性设置为true
(从而在模型上触发change
事件)。 - 当视图检测到
change
模型上的事件时,将render
调用该函数,该函数将 a 的背景图像替换为div
数据 URL。
骨干模型
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);
},
});
骨干视图
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") + ")"});
},
});
下面是 Chrome 时间线的屏幕截图。最大的延迟似乎发生在数据 URL 请求和加载事件之间(大约 0.5 秒)。我不确定“重新计算样式”是什么意思。我也不确定为什么会有这么多的绘制事件(它似乎在滚动条区域呈现)。
解决方案
我曾假设浏览器能够比任何 JavaScript 解决方案更有效地本地调整图像大小,但这种假设是错误的。通过在显示之前调整图像大小,我能够将延迟减少到大约50 毫秒。我使用了一个名为JavaScript Load Image的开源插件来处理图像加载和调整大小(它使用 HTML5canvas
标签)。这是我修改后的 Backbone 模型:
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});
},
});