Как ускорить сайт при помощи Javascript?

Как ускорить сайт при помощи Javascript?

Как ускорить сайт при помощи Javascript?

В то время, когда бОльшая часть веб-сёрфинга выполняется на телефоне или планшете, производительность имеет решающее значение. Не у всех есть флагманское устройство, и каждая задержка в отображении сайта на мобильных устройствах, может обернуться потерей клиента. К счастью, есть много способов использовать JavaScript, чтобы предотвратить это.

Работаем с {passive: true}

Чрезмерная прокрутка – явный признак того, что что-то происходит не так. В некоторых случаях браузер вынужден ждать, потому что EventListener’ы обращаются к странице. Такие события, как «wheel» или «touchmove», могут отменить прокрутку, поэтому страница должна дождаться завершения события до того, как начнется поведение прокрутки по умолчанию.
Это может привести к отрывистой и непоследовательной прокрутке, что приводит плохому взаимодействию приложения/сайта с пользователем.

document.addEventListener('touchmove', handler, {passive: true});

Чтобы обойти это, передайте объект {passive: true} в качестве третьего параметра при добавлении прослушивателя событий. Пометив событие как пассивное, браузер может предположить, что прокрутка не будет затронута, поэтому он сможет начать “слушать” немедленно.
Этот третий параметр заменяет параметр «useCapture» в старых браузерах, поэтому важно использовать функцию обнаружения при использовании этого типа слушателя. Чтобы преднамеренно отключить прокрутку, используйте «touch-action: none» в CSS, это решение работает в большинстве браузерах.
Задержка событий
Такие события, как прокрутка и изменение размера viewport’а, должны отрабатывать как можно быстрее, чтобы убедиться, что все прослушивание может оставаться в курсе остальных событий страницы. Если на каждом событии происходит что-то ресурсоемкое, это может быстро привести к “зависанию” страницы.

const resizeDebounce = debounce(() => {
// Code for resize event }, 200);
window.addEventListener('resize', resizeDebounce);

debouncing – это метод помогает задержать отработку кода, при большом количестве коллбеков от одного события. Например, мы можем увидеть мгновенное улучшение производительности на странице, если при помощи функции debounce, как в примере выше, сократим вызов события resize до 5 раз в секунду.

Обращаем внимание на viewport

Обычно событие прокрутки используется для определения того, когда элемент попадает в область отображения на странице. Даже при отладке вызов getBoundingClientRect() требует, чтобы браузер повторно проанализировал макет всей страницы. Есть новый API-браузер под названием IntersectionObserver, который передает видимость наблюдаемых элементов путем вызова функции каждый раз, когда они входят или выходят из зоны просмотра. Для сайтов, где реализован бесконечный скролинг вместо пагинации, этот API можно использовать в качестве флага для удаления или переработки старых представлений контента.
IntersectionObserver доступен во всех последних браузерах, кроме Safari. Этот API стоит того, так как разница в производительности очень заметна.
Отделяйте ресурсоемкие процессы
При работе с большими наборами данных или обработке больших файлов, таких как изображения, JavaScript может быстро заблокировать окно браузера. Вся работа выполняется в одном потоке поэтому, если этот поток занят, интерфейс не может обновиться.
Если вы знаете, что процесс займет много времени, то это хорошая идея для того, чтобы поместить его в web worker. Это скрипты, которые запускаются в отдельном потоке, что обеспечивает бесперебойную работу пользовательского интерфейса. Скрипты могут взаимодействовать друг с другом с помощью специального метода сообщений. Web worker’ы не имеют доступа к DOM и некоторым свойствам объекта window, поэтому эти сообщения могут использоваться для передачи самой необходимой информации.

Как продлить жизнь моему JavaScript-коду и сделать его надежным в будущем?

Одним из основных принципов JavaScript является то, что он всегда старается не “падать” и продолжать работу. Подавляющее большинство кода, написанных сегодня, по-прежнему будут функционировать десятилетие спустя, даже в этой постоянно меняющейся отрасли.
Однако из-за того, что блок кода работает, это не значит, что он надежен в будущем. Будет ли ваша кодовая база по-прежнему иметь смысл несколько лет спустя?

Избегайте “лапши” в вашем коде

При первом подходе в создании проекта может возникнуть соблазн написать весь код в одном месте. Хоть это и лучше понимать что делает каждый блок кода, но всё это будет представленно в виде “мешанины” в одном месте. Если другая область проекта нуждается в одной из функций, она будет либо скопирована, либо переписана. Если обнаружены ошибки или добавлена новая функция в основной файл кода, каждая версия нуждается в обновлении по отдельности, что может потребовать много времени.
Сохраняя модульность кода, дополнительная функциональность может быть включена там, где это необходимо. Как только код будет разбит на модули и компоненты, любые изменения можно будет проводить мгновенно. Такие методы, как шаблон модуля, могут быть реализованы без ущерба для остальной части проекта, что упрощает их реализацию.

Не зацикливайтесь на фреймворках

Многие современные структуры, такие как React или Polymer, побуждают разработчиков сохранять модульность благодаря созданию компонентов. У каждого есть свой способ общения между другими частями проекта.
Что произойдет, когда появится необходимость перейти на следующий “лучший” фреймворк? Переключение или даже просто обновление фреймворка могут быть трудоемкой задачей. Поиск новых способов совместной работы этих старых компонентов может съесть драгоценное время.
По возможности используйте собственные функции JavaScript для достижения результатов. Таким образом, при изменении фреймворков эти моменты трения минимизируются. Например, используйте объекты для обработки данных, прежде чем они будут переданы компоненту.
Это также помогает при написании универсального JavaScript. Избегая использования API-интерфейсов на основе браузера, где это возможно, код можно повторно использовать как в браузере, так и на сервере внутри узла.
Очистка
После написания модулей держите их в чистоте. Любой, кто читает их, должен понимать его функциональность, чтобы ускорить отладку.

let activeUsers = users.filter(user => user.active === true);

Самодокументирующий код – мощный инструмент для будущего кода. Например, использование описательных имен для переменных в итераторах может быть более понятным, чем общие имена типа «i».
Самое главное, быть последовательным. Придерживаясь единого стиля, весь код становится читаемым. Используйте руководство по стилю, чтобы определить, как должен выглядеть код и использовать такие инструменты, как ESLint, для соблюдения единого стиля написания кода.

Масштабируемость

Понятным должен быть не только код, но и структура проекта. Без этого понимания, со временем можно получить очень много ненужных проблем.
На старте, наличие файлов в одном каталоге все упрощает. Когда скрипты импортируют модули, нет путаницы в том, где они расположены.
По мере развития проектов большие массы файлов могут потеряться в огромных каталогах. Создавайте масштабируемую структуру например, сохраняйте все модули, которые имеют дело с пользователями в «каталоге пользователей». В конечном счете, реализация структуры зависит от проекта. Для одностраничного приложения необходимо разделять модель, представления и логику контроллера.
Покрываем тестами
Такие платформы, как React, поощряют создание небольших, многоразовых компонентов. Даже с масштабируемой структурой, не всегда можно быть уверенным в том, что все они все еще работают правильно. Для достижения бОльшей уверенности в своем коде, необходимо писать тесты.
Модульные тесты будут работать на уровне модуля. Такие инструменты, как Mocha и Jest, позволяют разработчикам определять ожидаемый результат для данного ввода. Периодически выполняемые эти тесты могут гарантировать отсутствие побочных эффектов.
Модули должны быть написаны таким образом, чтобы их можно было тестировать изолированно. Это означает наличие как можно большего количества внешних зависимостей и не полагаться на глобальное состояние.
Не стоит ограничивать себя интеграционными и функциональными тестами, ведь чем больше покрыт тестами проект, тем дольше он просуществует.
Javascript в будущем

Однако лучший способ для будущего кода – написать его в синтаксисе будущего. Хотя это может показаться шагом в неизвестность, есть инструменты, которые делают его максимально простым.
Babel – транспилер, который является инструментом, который преобразует одну форму JavaScript в другую. Это используется, чтобы преобразовать современный JS код стандарта ES6 и выше в формат ES5 для браузеров, которые пока еще не могут воспринимать новый синтаксис.
ES2015 привнесло много нового в JavaScript, которые могут помочь написать чистый код, например, функции стрелок, промисы и собственные модули. Последний стандарт – ES2017 – обеспечивает еще больше удобства благодаря асинхронным функциям. Учитывая правильные пресеты, Babel может помочь преобразовать все это в код, который будет использоваться уже сегодня.
Возможно в будущем, разработчики смогут пропустить шаг транспиляции вообще. Но на данный момент они обязаны подстраиваться под неумение браузеров распознавать синтаксис новых стандартов javascript’а.
Другие, но не менее важные вопросы по javascript

Что такое прототипное наследование и насколько оно полезно?

В JavaScript почти все является объектом. Каждый объект имеет прототип, из которого он наследует свойства и методы. Если объект не включает запрашиваемое свойство, JS будет искать его внутри своего прототипа. Он продолжает цепочку прототипов, пока не найдет совпадение, или не вернет ошибку.
Это полезно при создании объектов, которые имеют одни и те же значения и методы. Благодаря тому, что объекты ссылаются на прототип, требуется только одна их копия, что в свою очередь значительно снижает нагрузку на память.

var parent = {inherit: true}
var childA = Object.create(parent);
var childB = {};
Object.setPrototypeOf(childB, parent);
class childC extends parent {}

Прототипы могут быть добавлены к объектам при помощи Object.create () или Object.setPrototypeOf (). ES2015 имеет ключевое слово ‘class’, которое при использовании с ‘extends’ позволяет создать дочерний класс для уже существующего класса.

Как за счет Javascript увеличить доступность сайтов?

С современными вызовами по доступности веб-страниц, JavaScript и динамический контент вполне в состоянии справиться. Пока доступность (чтение веб-страниц для незрячих и т.д. прим. автора перевода) не является обязательным критерием для сайтов, Javascript может помочь этим технологиям стать более популярными, за счет усовершенствования текущих страниц.
Типовой способ помочь пользователям – обеспечить полезное управление фокусом. Например, календарь должен иметь возможность циклически перемещаться по дням с помощью клавиш со стрелками, при этом клавиши вверх и вниз пропускают неделю за одно нажатие. Это всего лишь частный случай перехвата событий клавиатуры, в то время как фокус находится внутри этого компонента.
В результате работы JavaScript’а мы можем добавлять важные изменения в данные, например обратная связь формы, также должны быть объявлены для экранных читателей (программы для слепых прим. автора перевода). Часто это достигается путем ARIA разметки контейнера

Что такое всплытие событий и как это отличается от захвата событий?

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

Первый этап – этап захвата – происходит, как только происходит событие. Он начинается от объекта на самом верхнем уровне, это либо «doc», либо «window» в зависимости от события. Оттуда он проходит через и все, что живет внутри него, пока не достигнет элемента, в котором произошло событие.
Затем происходит вторая фаза – фаза всплытия. Она повторяет этот процесс, но в обратном порядке, начиная с элемента, событие было вызвано и «всплывает» до самого верхнего элемента . Основное их отличие это то, что так называемый add.EventListener по умолчанию отлавливает события именно при всплытии.

Как “делегирование событий” улучшает код на сайтах с большим количеством интерактивных элементов?

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

parentEl.addEventListener('click', function(e) {
if(e.target  e.target.nodeName == 'BUTTON') {
// Button clicked
} });

Внутри обратного вызова события исходной целью этого события всегда будет «e.target», который может быть использован для принятия решения о том, что делать дальше. Например, атрибут данных может содержать идентификатор для ссылки на свойство объекта.

Что такое замыкание и чем оно может быть полезно при организации кода?

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

function outer() {
let x = 'Web Designer';
function shout() {
alert(`I love ${x}!`);
}
shout(); }

Вызов external () покажет ‘I love Web Designer!’, Но если вызов функции «shout» или переменная «х» определялись бы вне функции outer, то оба были бы неопределенны (undefined). Замыкание представляет собой комбинацию функции с ее лексическим окружением (другими словами зоной видимости прим. автора перевода). В этом случае зоной видимости функции shout() является код «внешней» функции outer.
Они полезны при создании нескольких компонентов, поскольку все, что объявлено внутри, не повлияет на других. Они могут использоваться для создания частных функций и переменных аналогично другим объектно-ориентированным языкам, таким как Python. В шаблоне модуля широко используются блокировки для обеспечения структурированных способов взаимодействия модулей.

Что означает «use strict» в верхней части блока кода?

ES5 представила необязательный вариант JavaScript под названием «строгий режим». В строгом режиме причуды более ранних версий будут вызывать ошибки, а не приводить к непреднамеренному поведению.

function strictFunction() {
'use strict';
myVar = 4; //ReferenceError }

Выше мы обращаемся к переменной, которая нигде не объявлена, ее попросту не существует. Вне строгого режима Javascript “позаботиться о нас” и создаст переменную myVar за нас и добавит ее в глобальную область, что в свою очередь, может перезаписать другие переменные или изменить поведение программы, которое было определенно ранее в скрипте. В строгом режиме это вызывает ошибку и останавливает выполнение кода. Модули ES2015 используют строгий режим по умолчанию, но в замыканиях, созданных с помощью функций, «use strict» может применяться как на уровне функции, так и на весь файл.

Что означает термин ‘hoisting’ в отношении JavaScript?

JavaScript уникален тем, что он не нуждается в компиляции перед распространением. Браузер будет компилировать скрипты по мере их обнаружения и делать заметки о любых функциях и переменных, объявленных внутри.
Затем браузер выполняет второй проход для выполнения кода, зная, где применяются эти функции и переменные. И когда браузер при втором обходе доходит до выполнения какой-либо функции, он “поднимает” информацию о ней, которую встретил при первом обходе, т.е. выполняет тот самый hoisting по отношению к этому блоку кода.

welcome("Matt"); //"Welcome, Matt."
function welcome(name) {
return `Welcome, ${name}.`;
}

В этом примере мы можем использовать функцию «welcome(name)», поскольку браузер выполнит эту функции при втором обходе и уже будет знать что именно нужно будет выполнить в данной блоке.

В чем разница между стрелочной функцией и регулярной функцией?

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

function CountUp() {
this.x = 0;
setInterval(() => console.log(++this.x), 1000); }
var a = new CountUp();

Ключевое отличие, помимо того, что запись функции стала чуть короче, заключается в том, что функции стрелок не создают своего собственного значения для «this». Вместо этого они будут использовать значение, которое есть внутри функции. В приведенном выше примере это функция вернет 1, 2, 3 и т. д. раз в секунду. При использовании обычной функцией без стрелок this.x не будет определен, поэтому на выходе получим NaN. Тело функции стрелки считается возвращаемым значением. Это делает их полезными для промисов, когда значения передаются. Регулярные функции должны явно возвращать значение или возвращать undefined.

Где я должен использовать ключевые слова ‘let’ и ‘const’ вместо ‘var’?

Другим фундаментальным изменением с ES2015 стало введение «let» и «const» в качестве альтернативных способов определения переменных. Переменные, объявленные таким образом, ограничены блоком, в котором они были определены. Это обеспечивает большую уверенность в том, что значения, созданные внутри разных блоков, не будут мешать внешнему коду.

for(let x=1; x<=3; x++) {
console.log(x); // 1, 2, 3}
console.log(x); // "x is not defined"

Если значение переменной не должно изменяться, используйте ‘const’ вместо ‘let’. Тогда при попытке переопределить константу будет выводиться ошибка. Объекты и переменные массива все еще могут меняться внутри, но не полностью заменяются.
И «let», и «const» не “поднимаются” (hoisting не работает), как «var», поэтому нельзя ссылаться на них, прежде чем они будут объявлены. Промежуток между началом блока выполнения и объявлением переменных называется «временная мертвая зона» и часто может быть источником путаницы.

Что такое функциональное программирование и чем оно отличается от прототипного?

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

Традиционно проекты JavaScript строятся с объектно-ориентированной структурой. Информация о текущем состоянии программы хранится в объектах, которые обновляются при изменении страницы.
Функциональное программирование дает другое мышление. Хотя такие языки, как F# (да-да, Эф шарп, не Си. прим. автора перевода), использовали его некоторое время, ES2015 привнес важные методы для JavaScript, который открывает эту методику для Интернета.
Все работы должны выполняться внутри «чистых» функций. Это функции, на которые не влияют никакие данные, выходящие за рамки этой функции. Другими словами, если одни и те же значения будут переданы функции, результат всегда будет неизменен.
Это также означает, что между функциями не может быть общего состояния. Любое состояние в приложении, которое необходимо использовать, должно передаваться как параметр функции, а не получать доступ непосредственно от него.
Наконец, код должен избегать изменения значений после их создания. Например, каждое изменение объекта должно возвращать копию этого объекта с измененным значением. Это делается для того, чтобы избежать побочных эффектов, которые могут вызвать ошибки и сделать код более сложным для тестирования.

>Автор оригинала: Matt Crouch, веб-разработчик из Лондона, является частью команды разработчиков платформы Cinolla - Activity Centre Management Software.
Оригинал статьи на английском от 24.10.17
Отставить отзыв

Ваш e-mail не будет опубликован. Обязательные поля помечены *