Подтвердить что ты не робот

Проблемы с производительностью при загрузке локальных изображений в браузер

Я использую 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 секунды). Я не знаю, что такое "Пересчитать стиль". Я также не уверен, почему так много событий рисования (это, как представляется, рендеринг в области полосы прокрутки).

Chrome Timeline

Решение

Я предположил, что браузер сможет изменять размеры изображений более эффективно, чем любое решение 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});
  },
});
4b9b3361

Ответ 1

Я столкнулся с такой же проблемой при загрузке больших изображений с помощью FileReader. Если вы не планируете отображать их в полном размере, кажется, что обходной путь включает масштабирование изображения перед его отображением с помощью элемента canvas.

После смешанного успеха с моей собственной реализацией я решил использовать Загрузка JavaScript JavaScript (лицензия MIT) и ее опцию maxWidth, которая решила это и многое другое (непредвиденные).

Попробуйте демонстрацию и посмотрите, хорошо ли загружаются ваши изображения.