Статьи

Создание веб-приложения с низким объемом памяти

С ростом количества мобильных устройств и планшетов веб-приложения часто загружаются в медленной и малой памяти. При создании веб-приложения можно подумать о выборе дизайна, который уменьшит объем памяти, потребляемой вашим приложением, чтобы пользовательский интерфейс оставался быстрым и отзывчивым.

Основная идея уменьшения занимаемой площади вашего приложения состоит в том, чтобы уменьшить объем кода в вашем приложении, тем самым уменьшая объем физической памяти, который он занимает. Это включает в себя функции, переменные, обработчики событий, служебный код и т. Д.

Совет 1: Используйте один прослушиватель событий поверх нескольких прослушивателей событий

Обычно для добавления прослушивателей событий к нескольким узлам одной группы обычно требуется следующее.

$("#list .countries").on("click", function() {
  $("box").value = this.innerHTML;
});

Если на вашем сайте 100 узлов, вы добавляете прослушиватель событий 100 раз. Это означает, что каждый из этих 100 узлов модифицируется для реагирования на событие onclick

В следующий раз подумайте о том, чтобы сделать это так:

 $("#list").on("click", function() {
  if($(this).hasClass("countries")) $("box").value = this.innerHTML;
});

При этом вам нужно только прослушать один родительский узел для события onclick

Совет 2: Используйте встроенные обработчики событий поверх внешних обработчиков событий

 <div onclick="menus.activate(event);">activate</div>

Этот совет наверняка заставит некоторых людей взволноваться. Считается само собой разумеющимся, что нужно переходить от встроенных обработчиков событий, потому что он смешивает поведение с контентом. Без уважения к причинам «наилучшей практики», по которым они не используются, вы обнаружите, что встроенные обработчики событий могут значительно сэкономить ваши ресурсы.

Прежде всего, вам не нужно будет писать код регистрации события (например, addEventListener()/removeEventListener() Вашему приложению также не нужно тратить время на выполнение вашего JavaScript (функции регистрации событий), который намного медленнее, чем собственный код (анализатор DOM). И как дополнительное преимущество, вам не придется беспокоиться об утечках памяти из-за того, что вы забыли отменить регистрацию обработчика, поскольку обработчик умирает вместе с узлом.

Вам также не нужно присваивать ID узлу, чтобы достичь его в своем коде, и вам не нужно проходить DOM, чтобы найти этот узел (метод, популяризированный jQuery). Вы просто сохранили там немного места, а также не позволяете приложению выполнять дополнительную работу.

И, поскольку встроенные обработчики событий могут сохранять контекст, это позволяет вам экономить память, устраняя необходимость создавать замыкания для инкапсуляции контекста. Вы можете не знать, но всякий раз, когда вы оборачиваете обработчик событий анонимной функцией, вы создаете это закрытие:

 node.addEventListener("click", function(e) {
  menus.activate(e);
}, false);

Некоторые библиотеки скрывают это за вспомогательной функцией, но, тем не менее, это та же проблема:

 node.addEventListener("click", menus.activate.bind(menus), false);

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

 <div onclick="menus.activate(event);">activate</div>

Совет 3: Используйте шаблоны поверх создания DOM

Если вы создаете что-то, кроме нескольких узлов, для создания дерева DOM путем присвоения строки HTML свойству innerHTMLdocument.createElement() И вам не нужно беспокоиться о том, что ваш HTML-контент ограничен вашим кодом JavaScript, потому что вы можете безопасно скрыть его на своем веб-сайте, как показано ниже.

 <body>
  <script type="text/html" id="mytemplate1">
    <div>hello</div>
  </script>
</body>

Обратите внимание, что содержимое HTML не будет отображаться, поскольку оно размещено внутри <script> Тег <script>text/html Вы можете получить строку с помощью следующего кода.

 var text = document.getElementById("mytemplate1").innerHTML;

Часто нам нужен не просто текст, а текст со встроенными символами, которые допускают динамические замены переменных. Это работа библиотеки шаблонов, и она делает создание DOM с использованием шаблонов намного более мощным. Небольшая библиотека шаблонов должна сократить ваши затраты на создание кода DOM в долгосрочной перспективе.

Совет 4: Рассмотрим синглтоны без состояния над объектами с состоянием

Приложения состоят из компонентов, и каждый компонент, как правило, представляет собой узел DOM, поддерживаемый объектом JavaScript для хранения данных. Чем больше компонентов, тем больше объектов JavaScript. Но если вы можете совместно использовать один и тот же объект JavaScript с несколькими узлами DOM, вы можете сэкономить некоторую память, повторно используя объект JavaScript. Достижение этого требует разработки ваших объектов JavaScript, которые будут вести себя как синглтоны. Компонент не будет иметь состояния и будет служить только для вызова синглтона для выполнения универсальной функции. Кроме того, он может хранить некоторые базовые данные в качестве атрибута на узле DOM, а синглтон может считывать эти данные с узла и воздействовать на него.

В более сложном сценарии узел DOM может сохранить уникальный идентификатор в качестве атрибута, а синглтон может сопоставить идентификатор со сложным объектом данных, хранящимся в другом месте. (Дальнейшая сложность лучше оставить для будущей статьи.)

Этот метод больше всего подходит для компонентов, в которых одновременно используется множество таких элементов, как элементы списка, или для компонентов, которые очень просты и не содержат состояний, таких как кнопки. Например:

 <input type="button" onclick="GenericButton.onclick(event);" data-command="copy">
 GenericButton.onclick = function(e) {
  e = e.target || e.srcElement;
  var cmd = e.getAttribute("data-command");
  if(cmd == "copy") //...
};

Совет 5: в полной мере использовать прототип наследования

Если вы создаете множество объектов одного типа, выберите прототип наследования вместо внедрения свойства. Когда вы вводите свойства в объект, вы копируете ссылки на каждый объект. Это заставляет число ссылок расти линейно с количеством объектов.

 function A() {
  this.value = 100;  //injecting value into this object
}
var obj1 = new A();
var obj2 = new A();

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

 function A() {
}
A.prototype.value = 100;
var obj1 = new A();
var obj2 = new A();

Совет 6: используйте систему публикации-подписки для упрощения связи

Вместо того, чтобы использовать шаблон наблюдателя (например, addActionListener() Шаблон публикации-подписки использует меньше кода для взаимодействия и позволяет вашему приложению быть более разъединенным, тем самым не требуя столько кода для поддержания связи. Существует множество реализаций системы публикации-подписки, доступных в сети, которые экономят память, которую вы можете использовать.

Совет 7: по возможности используйте меньшие библиотеки

Этот последний совет является наиболее очевидным. Большие библиотеки потребляют много памяти, а маленькие – меньше. Есть сайт, посвященный демонстрации крошечных библиотек, называемых microjs, где вы можете найти библиотеку, которая просто отвечает вашим потребностям и ничего более.