Używam FileReader do wyświetlania obrazów lokalnych w aplikacji Szkielet. Mniejsze obrazy są wyświetlane natychmiast, bez żadnych problemów, ale gdy zdjęcia mają kilka megabajtów lub więcej, ładowanie obrazu zajmuje dwa lub trzy sekundy (na zupełnie nowym MacBooku Pro z 8 GB pamięci RAM).Problemy z wydajnością podczas ładowania obrazów lokalnych do przeglądarki
Jak wskazano w komentarzach, duże obrazy ładują się natychmiast w this File API tutorial, więc problem nie jest związany z FileReader
, ale raczej z moją konkretną implementacją w szkielecie.
Dołączyłem odpowiedni model szkieletu i widok poniżej. Oto zarys logiki:
- Model tworzy nowy
FileReader
, w którym przekazywana jest ścieżka do pliku. - Po załadowaniu pliku zostanie utworzony
Image
, asrc
zImage
zostanie ustawiony na adres URL danych dostarczony przezFileReader
. - Po załadowaniu obrazu model jest aktualizowany o szerokość i wysokość obrazu (używany w innym miejscu w aplikacji), a atrybut
initialized
modelu jest ustawiony natrue
(w ten sposób wywołując zdarzeniechange
w modelu). - Gdy widok wykryje zdarzenie
change
w modelu, wywoływana jest funkcjarender
, która zastępuje obraz tła adresudiv
adresem URL danych.
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 Zobacz
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") + ")"});
},
});
Poniżej znajduje się zrzut ekranu z osi czasu Chrome. Wydaje się, że największe opóźnienie występuje między żądaniem adresu URL danych a zdarzeniem ładowania (wynosi to około 0,5 sekundy). Nie jestem pewien, o co w tym wszystkim chodzi "Zmień styl". Nie jestem również pewien, dlaczego jest tak wiele zdarzeń malowania (wydaje się, że renderowanie w obszarze paska przewijania).
ROZWIĄZANIE
Przypuszczałem, że przeglądarka będzie w stanie natywnie skuteczniej niż jakakolwiek zmiana rozmiaru obrazów rozwiązanie JavaScript, ale założenie to było błędne. Zmieniając rozmiar obrazów, które są wyświetlane, udało mi się zmniejszyć opóźnienie do około 50 milisekund. Użyłem wtyczki open source o nazwie JavaScript Load Image do obsługi ładowania i zmiany rozmiaru obrazu (używa znacznika HTML5 canvas
). Oto mój zmodyfikowany model szkieletu:
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});
},
});
To był dokładnie problem. Założęłem się, że przeglądarka byłaby bardziej wydajna przy zmianie rozmiaru obrazu natywnie zamiast wywoływania rozwiązania JavaScript. Tak jednak nie jest. Zmieniając rozmiar obrazu przed jego wyświetleniem, całkowicie wyeliminowałem opóźnienie. Wtyczka, którą zasugerowałeś, jest absolutnie idealna do tego scenariusza. Dzięki! –
Cieszę się, że pracował dla Ciebie, kudos do https://github.com/blueimp za ciężką pracę! – lazd