Я использую FileReader для отображения локальных изображений в приложении Backbone. Меньшие изображения отображаются немедленно без каких-либо проблем, но когда изображения имеют несколько мегабайт или больше, для загрузки изображения требуется Chrome 2 или 3 секунды (на новом MacBook Pro с 8 ГБ оперативной памяти).
Как отмечалось в комментариях, большие изображения мгновенно загружаются в этот файл API API, поэтому проблема не в FileReader
, а скорее с моей конкретной реализацией в Backbone.
Я включил соответствующую модель Backbone и рассмотрю ниже. Здесь схема логики:
- Модель создает новый
FileReader
, в который передается путь к файлу. - После загрузки файла создается
Image
, аsrc
дляImage
- URL-адрес данных, предоставляемыйFileReader
. - После загрузки изображения модель обновляется по ширине и высоте изображения (используется в другом месте приложения), а атрибут
initialized
модели устанавливается наtrue
(при этом заголовокchange
событие на модели). - Когда представление определяет событие
change
на модели, вызывается функцияrender
, которая заменяет фоновое изображение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 для обработки загрузки и изменения размера изображения (он использует тег HTML5 canvas
). Здесь моя модифицированная модель 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});
},
});