Javascript оптимизация цикла – движки рендеринга веб-страниц и советы по оптимизации их производительности / RUVDS.com corporate blog / Habr

Содержание

12 советов по улучшению производительности JavaScript-приложений / RUVDS.com corporate blog / Habr

Производительность — это один из важнейших вопросов, встающих перед разработчиками веб-страниц или веб-приложений. Никто не будет рад «падающему» от чрезмерной нагрузки приложению, или странице, которая загружается целую вечность. Пользователи веб-сайтов не готовы слишком долго ждать их загрузки или приведения их страниц в рабочее состояние. Согласно данным Kissmetrics, 47% посетителей ожидают, что веб-сайт загрузится менее чем за 2 секунды. 40% посетителей покинут сайт в том случае, если его загрузка займёт более 3 секунд.

Автор материала, перевод которого мы сегодня публикуем, говорит, что, если учитывать вышеприведённые цифры, становится ясно, что производительность — это то, о чём всегда стоит помнить веб-разработчикам. Здесь будут приведены 12 рекомендаций по улучшению производительности JS-проектов.

1. Пользуйтесь кэширующими механизмами браузеров


Существует два основных способа кэширования данных средствами браузеров. Первый — использование JavaScript-API Cache, работа с которым осуществляется с помощью сервис-воркеров. Второй — это обычный HTTP-кэш.

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

2. Оптимизируйте код в расчёте на те среды, в которых он будет выполняться


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

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

3. Избавляйтесь от неиспользуемого JS-кода


Благодаря удалению из проекта неиспользуемого кода улучшится не только время загрузки скриптов браузерами, но и время, необходимое браузерам на то, чтобы проанализировать и скомпилировать код. Для того чтобы избавиться от неиспользуемого кода стоит обратить внимание на особенности работы проекта. Так, если вы обнаружили некий функционал, с которым не работают пользователи — рассмотрите возможность убрать его из проекта, а заодно — и связанный с ним JS-код. В результате сайт будет загружаться быстрее, он будет быстрее подготавливаться к работе в браузере. Это благотворно скажется на тех впечатлениях, которые работа с сайтом вызовет у пользователей. Анализируя проект, учитывайте, что, например, некая библиотека, включённая в его состав, может быть включена в него по ошибке. Она вполне может реально в нём не использоваться. От неё стоит избавиться. То же самое касается использования неких зависимостей, которые реализуют то, что уже реализовано в современных браузерах. Как результат, переход на стандартные возможности браузеров, дублируемые этой зависимостью, поможет избавиться от ненужного кода.

4. Экономно расходуйте память


Стоит стремиться к тому, чтобы веб-проекты использовали бы лишь ту память, без которой они абсолютно не в состоянии обойтись. Дело в том, что разработчику нельзя заранее узнать о том, сколько памяти может быть доступно его приложению на некоем устройстве. Если приложение неоправданно использует большие объёмы памяти — это создаёт повышенную нагрузку на механизмы управления памятью браузерного JS-движка. В частности, это касается сборщика мусора. Частые вызовы сборщика мусора приводят к замедлению работы программ. Это негативно влияет на удобство работы с проектом.

5. Используйте механизмы отложенной загрузки для второстепенных скриптов


Пользователи хотят, чтобы веб-страницы загружались бы как можно быстрее. Но вряд ли для начального отображения страницы нужен абсолютно весь JS-код проекта. Если пользователю, чтобы задействовать некий код, нужно выполнить какое-то действие (например, щёлкнуть по некоему элементу или перейти на какую-нибудь вкладку в приложении), то загрузку этого кода можно отложить, выполнив её после первоначальной загрузки страницы и самых важных ресурсов.

При таком подходе можно избежать загрузки и компилирования браузером большого объёма JS-кода в самом начале работы, то есть — избежать замедления вывода страницы, вызванного необходимостью выполнения этих операций. После того, как завершится загрузка всего самого важного, можно начать загружать дополнительный код. В результате, когда этот код понадобится пользователю, он уже будет ему доступен. В соответствии с моделью RAIL Google рекомендует выполнять сеансы отложенной загрузки скриптов длительностью порядка 50 мс. При таком подходе операции по загрузке кода не повлияют на взаимодействие пользователя со страницей.

6. Избегайте утечек памяти


Если в вашем приложении случилась утечка памяти, то это выразится в том, что загруженная страница будет запрашивать у браузера всё больше и больше памяти. В результате потребление памяти этой страницей может достичь такого уровня, что это плохо повлияет на производительность всей системы. Вероятно, вы и сами сталкивались с подобной проблемой (и вам это, наверняка, не понравилось). Вполне возможно, что страница, на которой имелась утечка памяти, содержала некое средство просмотра изображений — вроде слайдера или «карусели».

В инструментах разработчика Chrome можно проанализировать сайт на предмет утечек памяти. Делается это путём исследования показателей средствами вкладки Performance. Обычно утечки памяти исходят из-за фрагментов DOM, удалённых со страницы, но привязанным к каким-то переменным. Это не позволяет сборщику мусора очистить память, занимаемую данными ненужными фрагментами DOM.

7. Если вам нужно выполнить некие тяжёлые вычисления — используйте веб-воркеры


Из материалов ресурса MDN можно узнать о том, что веб-воркеры позволяют запускать код в фоновом потоке, отделённом от главного потока веб-приложения. Преимущество такого подхода заключается в том, что тяжёлые вычисления могут быть выполнены в отдельном потоке. Это позволяет главному потоку (обычно ответственному за обеспечение работы пользовательского интерфейса) выполняться без блокировок и замедлений.

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

8. Если вы обращаетесь к элементу DOM несколько раз — сохраните ссылку на него в переменной


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

9. Стремитесь объявлять переменные в той же области видимости, в которой они будут использоваться


JavaScript, при попытке доступа к переменной, сначала ищет её в локальной области видимости. Если её там не оказывается — поиск продолжается в областях видимости, в которую вложена локальная область видимости. Так происходит до тех пор, пока проверке не подвергнутся глобальные переменные. Сохранение переменных в локальных областях видимости ускоряет доступ к ним.

Постарайтесь, без особой необходимости, не использовать при объявлении переменных ключевое слово var. Используйте вместо него, для объявления, соответственно, переменных и констант, ключевые слова let и const

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

10. Старайтесь не использовать глобальные переменные


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

11. Применяйте в JavaScript оптимизации кода, которые вы применяли бы и к программам, написанным на других языках


  • Всегда применяйте алгоритмы с наименьшей из возможных вычислительной сложностью, решайте задачи с использованием оптимальных структур данных.
  • Оптимизируйте используемые алгоритмы, стремясь получить те же результаты, выполнив меньше вычислений.
  • Избегайте рекурсивных вызовов.
  • Оформляйте повторяющиеся фрагменты вычислений в виде функций.
  • Упрощайте математические вычисления.
  • Используйте поисковые массивы вместо конструкций switch/case.
  • Стремитесь к тому, чтобы условия, проверяемые в условных конструкциях, чаще принимали бы истинные значения. Это способствует более эффективному использованию возможностей процессора по упреждающему исполнению команд.
  • Если у вас есть возможность использовать для выполнения неких действий побитовые операторы — сделайте это. На выполнение подобных вычислений уходит меньше ресурсов процессора.

12. Используйте инструменты для исследования производительности приложений


Для исследования различных аспектов веб-проектов можно порекомендовать инструмент Lighthouse. Он выставляет приложению оценки по следующим показателям: Performance, Progressive Web App, Accessibility, Best Practices, SEO. Lighthouse не только выставляет оценки, но и даёт рекомендации по улучшению проекта. Ещё одно средство для анализа производительности, Google PageSpeed, создано для того, чтобы помочь разработчикам исследовать свои сайты и увидеть направления их возможного улучшения.

И Lighthouse, и PageSpeed — инструменты не идеальные, но их использование помогает увидеть проблемы, которые, на первый взгляд, могут оказаться незаметными.

В меню Chrome можно найти команду, открывающую диспетчер задач. Там выводятся сведения о системных ресурсах, используемых открытыми вкладками браузера. Более подробные сведения о том, что происходит на странице, можно получить, открыв вкладку Performance инструментов разработчика Chrome (подобные инструменты есть и в других браузерах). Эта вкладка позволяет анализировать множество показателей, касающихся производительности сайта.


Вкладка Performance в инструментах разработчика Chrome

В ходе сбора сведений о производительности страниц средствами Chrome можно настраивать доступные страницам процессорные и сетевые ресурсы, что позволяет выявлять и исправлять проблемы.


Анализ производительности страницы в Chrome

Для того чтобы глубже проанализировать веб-сайт — можно воспользоваться API Navigation Timing. Оно позволяет выполнять измерения различных показателей прямо в коде приложения.

Если вы разрабатываете на JavaScript серверные проекты с использованием Node.js, то вам, для глубокого анализа своих приложений, можно воспользоваться платформой NodeSource. Измерения, проводимые средствами этой платформы, оказывают незначительное воздействие на проект. В среде Node.js, как и в браузере, может возникать множество проблем — вроде тех же утечек памяти. Анализ проектов, основанных на Node.js, помогает выявлять и устранять проблемы с их производительностью.

Итоги


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

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

Уважаемые читатели! Как вы оптимизируете свои JS-проекты?

движки рендеринга веб-страниц и советы по оптимизации их производительности / RUVDS.com corporate blog / Habr

Сегодня, в переводе одиннадцатой части серии материалов, посвящённых JavaScript, мы поговорим о подсистемах браузера, ответственных за рендеринг веб-страниц. Они играют ключевую роль в деле преобразования описаний документов, выполненных с помощью HTML и CSS, в то, что мы видим на экране.

Автор материала говорит, что в компании SessionStack приходится уделять рендерингу огромное внимание. В этой статье он поделится советами, касающимися оптимизации веб-страниц с учётом особенностей их визуализации.

[Советуем почитать] Другие 19 частей цикла

Обзор


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

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


Основные компоненты браузера
  • Пользовательский интерфейс (User Interface). Этот компонент браузера включает в себя адресную строку, кнопки «Вперёд» и «Назад», команды для работы с закладками, и так далее. В целом, это всё то, что выводит на экран браузер — за исключением той области его окна, где находится отображаемая им веб-страница.
  • Движок браузера (Browser Engine). Он занимается поддержкой взаимодействия между пользовательским интерфейсом и движком рендеринга.
  • Движок рендеринга (Rendering Engine). Эта подсистема отвечает за показ веб-страницы. Движок рендеринга обрабатывает HTML и CSS и выводит то, что у него получилось, на экран.
  • Сетевая подсистема (Networking). Эта подсистема ответственна за сетевое взаимодействие браузера с внешним миром, в частности, например, её средствами выполняются XHR-запросы. Она поддерживает платформенно-независимый интерфейс, за которым скрываются конкретные реализации различных сетевых механизмов, специфичные для различных платформ. Здесь можно почитать подробности об этой подсистеме.
  • Подсистема поддержки пользовательского интерфейса (UI Backend). Эта подсистема отвечает за вывод базовых компонентов интерфейса, таких, как окна и элементы управления, вроде чекбоксов. Здесь браузеру предоставляется универсальный интерфейс, не зависящий от платформы, на которой он работает, а в основе этой подсистемы лежат возможности формирования элементов пользовательского интерфейса, предоставляемые конкретной операционной системой.
  • JavaScript-движок (JavaScript Engine). Мы разбирали JS-движок в одном из предыдущих материалов этой серии. Именно здесь осуществляется выполнение JS-кода.
  • Подсистема постоянного хранения данных (Data Persistence). Если приложению нужны возможности локального хранения данных, оно может пользоваться различными механизмами, предоставляемыми этой подсистемой. Среди них, например, такие API, как localStorage, IndexedDB, WebSQL и FileSystem.

В этом материале мы сосредоточимся на движке рендеринга. Именно эта подсистема браузера занимается разбором и визуализацией HTML и CSS. А это — именно те технологии, с которыми постоянно взаимодействует код веб-приложений, написанный на JavaScript.

О различных движках рендеринга


Главная задача движка рендеринга заключается в том, чтобы вывести запрошенную страницу в окне браузера. Движок может выводить HTML-документы, XML-документы, изображения. При использовании дополнительных плагинов движок может визуализировать и материалы других типов, например — PDF-документы.

Мы знаем, что существуют различные JS-движки, которые используют различные браузеры. То же самое справедливо и для движков рендеринга. Вот несколько популярных движков:

  • Gecko — используется в браузере Firefox.
  • WebKit — применяется в браузере Safari.
  • Blink — интегрирован в браузеры Chrome и Opera (с 15-й версии).

Процесс рендеринга веб-страницы


Движок рендеринга получает содержимое запрошенного документа от сетевого уровня браузера. Процесс рендеринга выглядит так, как показано на рисунке ниже.
Процесс рендеринга веб-страницы

Вот основные этапы этого процесса:

  • Обработка HTML для создания дерева DOM.
  • Создание дерева рендеринга.
  • Расчёт параметров расположения элементов дерева рендеринга на экране, формирование макета страницы.
  • Визуализация (отрисовка) дерева рендеринга.

Рассмотрим эти и другие шаги, выполняемые при визуализации веб-страниц, подробнее.

Создание дерева DOM


Первый этап работы движка рендеринга заключается в разборе HTML-документа и преобразовании того, что у него получилось, в узлы DOM, размещённые в дереве DOM. При этом веб-страница, которая представлена в виде HTML-кода, преобразуется в структуру, подобную той, которая показана на рисунке ниже.
Дерево DOM

Каждый элемент этого дерева, содержащий вложенные элементы, является для них родительским. Это справедливо для всех уровней вложенности.

Создание дерева CSSOM


CSSOM (CSS Object Model) — это объектная модель CSS. Когда браузер занимается созданием дерева DOM страницы, он находит в разделе head тег link, который ссылается на внешний CSS-файл, скажем, имеющий имя theme.css. Ожидая, что этот ресурс может понадобиться ему для рендеринга страницы, браузер выполняет запрос на загрузку данного файла. Этот файл содержит в себе обычный текст, представляющий собой описание стилей, применяемых к элементам страницы.

Как и в случае с HTML, движку нужно конвертировать CSS в нечто, с чем может работать браузер — в CSSOM. В результате получается дерево CSSOM, представленное на следующем рисунке.


Дерево CSSOM

Знаете, почему CSSOM имеет древовидную структуру? Когда выполняется формирование итогового набора стилей для элемента страницы, браузер начинает с наиболее общих правил, применимых к этому элементу, представленному узлом DOM (например, если узел является потомком элемента body, к нему применяются все стили, заданные для body), а затем рекурсивно уточняет вычисленные стили, применяя более специфические правила.

Разберём пример, который представлен на предыдущем рисунке. Любой текст, содержащийся внутри тега span, который помещён в элемент body, выводится красным цветом и имеет размер шрифта, равный 16px. Эти стили унаследованы от элемента body. Если элемент span является потомком элемента p, значит его содержимое не выводится в соответствии с применённым к нему более специфичным стилем.

Кроме того, обратите внимание на то, что вышеприведённое дерево не является полным CSSOM-деревом. Тут показаны лишь стили, которые мы, в нашем CSS-файле, решили переопределить. У каждого браузера имеется стандартный набор стилей, применяемый по умолчанию, известный ещё как «стили пользовательского агента» (user agent styles). Именно результаты применения этих стилей можно видеть на странице, не имеющей связанных с ней CSS-правил. Наши же стили просто переопределяют некоторые из стандартных стилей браузера.

Создание дерева рендеринга


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

Что это такое? Это — дерево визуальных элементов, созданных в том порядке, в котором они будут выводиться на экран. Это — визуальное представление HTML-кода страницы, отражающее влияние соответствующих этой странице CSS-правил. Цель этого дерева заключается в том, чтобы обеспечить вывод элементов правильном порядке.

Узел дерева рендеринга известен в движке WebKit как «renderer» или «render object» (мы будем называть их «объектами рендеринга»).

Вот как будет выглядеть дерево рендеринга для деревьев DOM и CSSOM, показанных выше.


Дерево рендеринга

Вот общее описание действий браузера, выполняемых им при создании дерева рендеринга.

  • Начиная с корня дерева DOM, браузер обходит каждый видимый узел. Некоторые узлы невидимы (например — теги, содержащие ссылки на скрипты, мета-теги, и так далее), их браузер пропускает, так как они не влияют на внешний вид страницы. Некоторые узлы скрыты средствами CSS, браузер так же не включает их в дерево рендеринга. Например, узел span из нашего примера не выводится в дереве рендеринга, так как у нас имеется явным образом заданное правило, устанавливающего для него свойство display: none.
  • Для каждого видимого узла браузер находит подходящие CSSOM-правила и применяет их.
  • В результате формируется структура, содержащая видимые узлы и вычисленные для них стили.

Для того, чтобы лучше понять то, о чём тут идёт речь, можете взглянуть на исходный код класса RenderObject из WebKit. Каждый объект рендеринга представляет собой прямоугольную область, обычно соответствующую CSS-блоку узла. Сведения об этом блоке включают его геометрические характеристики, такие, как ширина, высота и позиция.

Формирование макета страницы


После того, как объект рендеринга создан и добавлен в дерево, ему пока ещё не назначены позиция и размер. Вычисление этих значений и называется формированием макета страницы.

HTML использует потоковую модель компоновки. Это означает, что чаще всего система может вычислить геометрические параметры элементов за один проход. Тут используется координатная система, основанная на корневом объекте рендеринга, в ней применяются координаты left и top.

Формирование макета — это рекурсивный процесс. Он начинается в корневом объекте, который соответствует элементу документа <html>. Процесс выполняется рекурсивно по всей иерархической структуре объекта рендеринга, производится вычисление размеров и положения для каждого элемента, который в этом нуждается.

Позиция корневого объекта рендеринга — 0,0. Его размеры соответствуют размерам видимой части окна браузера (это называют «областью просмотра», viewport).

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

Визуализация дерева рендеринга


На данном этапе осуществляется обход дерева рендеринга и вызов методов paint() объектов рендеринга, которые и выполняют вывод графического представления объектов на экран.

Визуализация, или отрисовка, может быть глобальной или инкрементной (так же выполняется и формирование макета страницы).

  • Глобальная отрисовка означает повторный вывод всего дерева рендеринга.
  • Инкрементная отрисовка выполняется в ситуации, когда меняются лишь некоторые из объектов рендеринга, причём так, что это не влияет на всё дерево. Подсистема рендеринга делает недействительными прямоугольные области на экране. Это приводит к тому, что операционная система воспринимает их как участки, содержимое которых нужно обновить и сгенерировать для них событие paint. Операционная система выполняет перерисовку областей интеллектуально, объединяя несколько областей в одну.

В целом, важно понимать, что визуализация — это поэтапный процесс. Для улучшения восприятия страницы пользователями движок рендеринга стремится к тому, чтобы вывести страницу на экран как можно скорее. Он не будет ждать до тех пор, пока будет разобран весь HTML, для того, чтобы приступить к формированию дерева рендеринга и к расчёту параметров макета страницы. В результате некоторые части страницы окажутся обработанными и выведенными на экран, в то время как движок рендеринга продолжит работу с оставшимся содержимым страницы, которое поступает из сети.

Порядок обработки JS-скриптов и CSS-файлов


Разбор и выполнение скрипта осуществляется сразу же после того, как система обработки кода страницы достигнет тега <script>. Обработка документа приостанавливается до тех пор, пока скрипт не будет выполнен. Это означает, что данный процесс выполняется синхронно.

Если скрипт получают из внешнего источника, то сначала он должен быть загружен через сеть (тоже синхронно). Обработка страницы приостанавливается до тех пор, пока загрузка скрипта не будет завершена.

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

Оптимизация производительности рендеринга


Если вы хотите оптимизировать своё приложение с учётом особенностей рендеринга страниц, существует пять основных областей, которые вы можете контролировать, и на которые нужно обратить внимание.
  • JavaScript. В предыдущих материалах этой серии мы рассказывали о том, как писать оптимизированный JS-код, не блокирующий пользовательский интерфейс, эффективно использующий память и реализующий другие полезные техники. Когда речь идёт о рендеринге, нам нужно учитывать то, как JS-код будет взаимодействовать с элементами DOM на странице. JavaScript может вносить множество изменений в пользовательский интерфейс, особенно если речь идёт об одностраничных приложениях.
  • Вычисление стилей. Это — процесс определения того, какое CSS-правило применяется к конкретному элементу с учётом соответствующих этому элементу селекторов. После определения правил осуществляется их применение и вычисление итогового стиля для каждого элемента.
  • Формирование макета страницы. После того, как браузер узнает о том, какие стили применяются к элементу, он может приступить к вычислению того, как много места на экране займёт этот элемент, и к нахождению его позиции. Модель макета веб-страницы указывает на то, что одни элементы могут влиять на другие элементы. Например, ширина элемента <body> может влиять на ширину дочерних элементов, и так далее. Всё это означает, что процесс формирования макета — это задача, требующая интенсивных вычислений. Кроме того, вывод элементов выполняется на множество слоёв.
  • Отрисовка. Именно здесь выполняется преобразование всего, что было вычислено ранее, в пиксели, выводимые на экран. Этот процесс включает в себя вывод текста, цветов, изображений, границ, теней, и так далее. Речь идёт о каждой видимой части каждого элемента.
  • Компоновка. Так как части страницы вполне могут быть выведены на различных слоях, их требуется совместить в едином окне в нужном порядке, что приведёт к правильному выводу страницы. Это очень важно, особенно — для перекрывающихся элементов.

Оптимизация JS-кода


JavaScript-код часто приводит к изменению того, что можно наблюдать в браузере. Особенно это актуально для одностраничных приложений. Вот несколько советов, касающихся оптимизации JS для улучшения процесса рендеринга страниц.
  • Избегайте использования функций setTimeout() и setInterval() для обновления внешнего вида элементов страниц. Эти функции вызывают коллбэк в некоторый момент формирования кадра, возможно, в самом конце. Нам же нужно вызвать команду, приводящую к визуальным изменениям, в начале кадра, и не пропустить его.
  • Переносите длительные вычисления в веб-воркеры.
  • Используйте для выполнения изменений в DOM микро-задачи, разбитые на несколько кадров. Этим следует пользоваться тогда, когда задача нуждается в доступе к DOM, а доступ к DOM, из веб-воркера, например, получить нельзя. Это означает, что большую задачу нужно разбить на более мелкие и выполнять их внутри requestAnimationFrame, setTimeout, или setInterval, в зависимости от особенностей задачи.

Оптимизация CSS


Модификация DOM путём добавления и удаления элементов, изменения атрибутов и других подобных действий приведёт к тому, что браузеру придётся пересчитать стили элементов, и, во многих случаях, макет всей страницы, или, по крайней мере, некоторой её части. Для оптимизации процесса рендеринга страницы учитывайте следующее.
  • Уменьшите сложность селекторов. Использование сложных селекторов может привести к тому, что работа с ними займёт более 50% времени, необходимого для вычисления стилей элемента, остальное время уйдёт на конструирование самого стиля.
  • Уменьшите число элементов, для которых нужно выполнять вычисление стилей. То есть, лучше, если изменение стиля будет направлено на несколько элементов, а не на всю страницу.

Оптимизация макета


Пересчёт макета страницы может требовать серьёзных системных ресурсов. Для оптимизации этого процесса примите во внимание следующее.
  • Уменьшите число ситуаций, приводящих к пересчёту макета. Когда вы меняете стили, браузер выясняет, требуется ли пересчёт макета для отражения этих изменений. Изменения свойств, таких, как ширина, высота, или позиция элемента (в целом, речь идёт о геометрических характеристиках элементов), требуют изменения макета. Поэтому, без крайней необходимости, не меняйте подобные свойства.
  • Всегда, когда это возможно, используйте модель flexbox вместо более старых моделей создания макетов. Эта модель работает быстрее, чем другие, что может дать значительный прирост производительности.
  • Избегайте модели работы с документом, предусматривающей периодическое изменение параметров элементов и их последующее считывание. В JavaScript доступны параметры элементов DOM (вроде offsetHeight или offsetWidth) из предыдущего кадра. Считывание этих параметров проблем не вызывает. Однако, если вы, до чтения подобных параметров, меняете стиль элемента (например, динамически добавляя к нему какой-то CSS-класс), браузеру потребуется потратить немало ресурсов для того, чтобы применить изменения стиля, создать макет и возвратить в программу нужные данные. Это может замедлить программу, подобного стоит избегать всегда, когда это возможно.

Оптимизация отрисовки


Часто эта задача отнимает больше всего времени, поэтому важно избегать ситуаций, приводящих к перерисовке страницы. Вот что здесь можно сделать.
  • Изменение любого свойства, за исключений трансформаций и изменений прозрачности, приводит к перерисовке. Используйте эти возможности умеренно.
  • Если ваши действия вызвали пересчёт макета, это приводит и к вызову перерисовки страницы, так как изменения геометрических параметров элемента ведут и к его визуальным изменениям.
  • Уменьшайте области страниц, которые необходимо перерисовывать, грамотно управляя расположением слоёв и анимацией.

Итоги


В этом материале мы поговорили о подсистемах рендеринга современных браузеров. Правильный подход к визуализации страниц ведёт к повышению производительности веб-приложений и к улучшению впечатлений пользователей от работы с ними.

Предыдущие части цикла статей:

Часть 1: Как работает JS: обзор движка, механизмов времени выполнения, стека вызовов
Часть 2: Как работает JS: о внутреннем устройстве V8 и оптимизации кода
Часть 3: Как работает JS: управление памятью, четыре вида утечек памяти и борьба с ними
Часть 4: Как работает JS: цикл событий, асинхронность и пять способов улучшения кода с помощью async / await
Часть 5: Как работает JS: WebSocket и HTTP/2+SSE. Что выбрать?
Часть 6: Как работает JS: особенности и сфера применения WebAssembly
Часть 7: Как работает JS: веб-воркеры и пять сценариев их использования
Часть 8: Как работает JS: сервис-воркеры
Часть 9: Как работает JS: веб push-уведомления
Часть 10: Как работает JS: отслеживание изменений в DOM с помощью MutationObserver

Уважаемые читатели! Какие приёмы вы применяете для оптимизации рендеринга страниц ваших веб-проектов?

Оптимизация Javascript-кода

Оптимизировать код javascript, конечно, надо не везде. Обычно - в ускорении нуждаются

  • интерфейсные компоненты
    • анимация
    • драг'н'дроп
  • обработчики частых событий
    • onmousemove
    • CSS expression (IE)

Основные узкие места - как правило, там, где javascript вызывается очень часто. Мы рассмотрим основные причины тормозов и то, как их преодолеть.

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

Любое обращение к DOM - обычно тяжелее для браузера, чем обращение к переменной javascript. Изменение свойств, влияющих на отображение элемента: className, style, innerHTML и ряда других - особенно сложные операции.

Уменьшение их числа может ускорить скрипт.

Например, эта функция строит элементарный интерфейс:

function buildUI(parent)  {
	parent.innerHTML = ''
	parent.innerHTML += buildTitle()
	parent.innerHTML += buildBody()
	parent.innerHTML += buildFooter()
}

Оптимизация по части доступа к innerHTML будет такая:

function buildUI2(parent) {
	var elementText = ''
	elementText += buildTitle()
	elementText += buildBody()
	elementText += buildFooter()
	parent.innerHTML = elementText
}

Нажатие на кнопку запускает многократный запуск функции и замер общего времени. В разных браузерах разница во времени выполнения будет разной.

время buildUI

время buildUI2

Рассмотрим функцию, которая проходит всех детей узла и ставит им свойства:

function testAttachClick(parent) {

	var elements = parent.getElementsByTagName('div')

	for(var i=0; i<elements.length; i++) {
		elements[i].onclick = function() { 
			alert('click on '+this.number) 
		}
		elements[i].number = i
	}
}

Сколько в ней обращений к DOM ?

Правильный ответ - 4 обращения.

Первое - самое очевидное:

var elements = parent.getElementsByTagName('div')

Функция getElementsByTagName() возвращает специальный объект NodeList, который похож на массив: есть длина и нумерованы элементы, но на самом деле это динамический объек

Оптимизация хвостовой рекурсии в JavaScript / Habr

Привет, читатель.

Иногда для решении задачи приходится использовать Рекурсию, в которой есть свои плюсы и минусы. Я столкнулся с проблемой переполнения стека.

Максимальная глубина рекурсии ограничена движком JavaScript. Точно можно рассчитывать на 10000 вложенных вызовов, некоторые интерпретаторы допускают и больше, но для большинства из них 100000 вызовов – за пределами возможностей. Существуют автоматические оптимизации, помогающие избежать переполнения стека вызовов («оптимизация хвостовой рекурсии»), но они ещё не поддерживаются везде и работают только для простых случаев.

Пример рекурсивной функции:
function sum(n) {
  return n === 0 ? 0 : n + sum(n - 1)
}

sum(5) // 1 + 2 + 3 + 4 + 5  = 15
sum(100000) // Error: Maximum call stack size exceeded.


Хвостовая рекурсия позволяет оптимизировать вызовы компилятором и уже есть в стандарте ES6, но поддержка браузерами оставляет желать лучшего.

Пример хвостовой рекурсивной функции:

function sum(number, s = 0){
  return number === 0 ? s : sum(number - 1, s + number)
}

Но, без поддержки браузерами мы столкнемся с той же проблемой — переполнения стека. Можем попробовать использовать вместе с Trampolining.

Напишем декоратор, который будет принимать измененную рекурсивную функцию(следующий шаг) и исполнять ее в цикле, без увеличения глубины вызовов.

function trampoline(fn) {
  return function(...args) {
    let result = fn.apply(fn.context, args)
    while (typeof result === 'function') {
      result = result()
    }

    return result
  }
}

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

function sum(number, s = 0) {
  return number === 0 ? s : () => sum(number - 1, s + number)
}

Используем:

const trampolineSum = trampoline(sum)
trampolineSum(100000) // 5000050000

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

Спасибо, за внимание. Хорошего дня 🙂

Update
Производительность:

#1 Рекурсия

Код #1
function sum(n) {
  return n === 0 ? 0 : n + sum(n - 1)
}

console.time("run")
sum(1000)
console.timeEnd("run")


Результат #1 Safari 12.1.2

[Debug] run: 0.353ms
[Debug] run: 0.281ms
[Debug] run: 0.305ms
[Debug] run: 0.315ms
[Debug] run: 0.319ms
[Debug] run: 0.231ms
[Debug] run: 0.255ms
[Debug] run: 0.334ms
[Debug] run: 0.370ms
[Debug] run: 0.274ms
[Debug] run: 0.260ms


Результат #1 Google Chrome 78.0.3892.0

run: 0.118896484375ms
run: 0.101806640625ms
run: 0.099853515625ms
run: 0.10205078125ms
run: 0.10302734375ms
run: 0.099853515625ms
run: 0.106201171875ms
run: 0.103759765625ms
run: 0.105224609375ms
run: 0.262939453125ms
run: 0.136962890625ms
run: 0.10107421875ms
run: 0.10302734375ms

#2 Итерация

Код #2
function sum(n) {
  let sum = 0
  for (let i = 1; i <= n; i++) {
    sum += i
  }

  return sum
}

console.time("run")
sum(1000)
console.timeEnd("run")


Результат #2 Safari 12.1.2

[Debug] run: 0.562ms
[Debug] run: 0.552ms
[Debug] run: 0.502ms
[Debug] run: 0.527ms
[Debug] run: 0.434ms
[Debug] run: 0.462ms
[Debug] run: 0.511ms
[Debug] run: 0.528ms
[Debug] run: 0.549ms
[Debug] run: 0.475ms
[Debug] run: 0.530ms
[Debug] run: 0.494ms


Результат #2 Google Chrome 78.0.3892.0

run: 0.932861328125ms
run: 0.751953125ms
run: 0.4580078125ms
run: 0.678955078125ms
run: 0.424072265625ms
run: 0.505859375ms
run: 0.563720703125ms
run: 0.404052734375ms
run: 0.411865234375ms
run: 0.634033203125ms
run: 0.4169921875ms
run: 0.390869140625ms
run: 0.464111328125ms

#3 Хвостовая рекурсия и «батут»

Код #3
function trampoline(fn) {
  return function(...args) {
    let result = fn.apply(fn.context, args)
    while (typeof result === 'function') {
      result = result()
    }

    return result
  }
}

function sum(number, s = 0) {
  return number === 0 ? s : () => sum(number - 1, s + number)
}

const trampolineSum = trampoline(sum)
console.time("run")
trampolineSum(1000)
console.timeEnd("run")


Результат #3 Safari 12.1.2

[Debug] run: 0.936ms
[Debug] run: 0.792ms
[Debug] run: 0.882ms
[Debug] run: 0.826ms
[Debug] run: 0.968ms
[Debug] run: 0.818ms
[Debug] run: 1.681ms
[Debug] run: 0.777ms
[Debug] run: 1.109ms
[Debug] run: 0.832ms
[Debug] run: 0.826ms


Результат #3 Google Chrome 78.0.3892.0

run: 0.60888671875ms
run: 0.989990234375ms
run: 0.567138671875ms
run: 0.56005859375ms
run: 1.0087890625ms
run: 0.5400390625ms
run: 0.578125ms
run: 0.541015625ms
run: 0.557861328125ms
run: 1.97607421875ms
run: 0.570068359375ms
run: 0.593017578125ms
run: 0.530029296875ms
run: 0.89794921875ms
run: 0.590087890625ms

#4 Хвостовая рекурсия и «батут» (большое число)

Код #4
function trampoline(fn) {
  return function(...args) {
    let result = fn.apply(fn.context, args)
    while (typeof result === 'function') {
      result = result()
    }

    return result
  }
}

function sum(number, s = 0) {
  return number === 0 ? s : () => sum(number - 1, s + number)
}

const trampolineSum = trampoline(sum)
console.time("run")
trampolineSum(100000)
console.timeEnd("run")


Результат #4 Safari 12.1.2

[Debug] run: 33.693ms
[Debug] run: 24.564ms
[Debug] run: 25.313ms
[Debug] run: 23.262ms
[Debug] run: 24.848ms
[Debug] run: 23.909ms
[Debug] run: 24.248ms
[Debug] run: 32.416ms
[Debug] run: 24.090ms
[Debug] run: 23.986ms


Результат #4 Google Chrome 78.0.3892.0

run: 40.73681640625ms
run: 33.955078125ms
run: 40.907958984375ms
run: 37.693115234375ms
run: 28.929931640625ms
run: 30.7548828125ms
run: 29.720947265625ms
run: 40.8310546875ms
run: 31.5830078125ms
run: 30.712890625ms
run: 30.162841796875ms
run: 31.56103515625ms

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

Оптимизация node.js приложения / Habr

Дано: старое http node.js приложение и возросшая нагрузка на него.

Стандартные решения проблемы: докинуть серверов, все переписать с 0, оптимизировать уже написанное.

Давайте попробуем пойти путем оптимизации и разобраться, как можно найти и улучшить слабые места приложения. А быть может ускориться не трогая ни строчки кода 🙂

Всех заинтересованных добро пожаловать под кат!

Для начала определимся с методикой тестирования производительности. Нас будет интересовать количество обслуженных запросов за 1 секунду: rps.

Запускать будем приложение в режиме 1 воркера (1 процесса), замеряя производительность старого кода и кода с оптимизациями — абсолютная производительность не важна, важна сравнительная производительность.

В типичном приложении с множествами разных роутов логично сначала найти самые загруженные запросы, на обработку которых тратится большая часть времени. Утилы вида request-log-analizer или множество подобных позволят извлечь эту информацию из логов.

С другой стороны, можно взять реальный список запросов и пулять их все (например с помощью yandex-tank-а) — получим достоверный профиль нагрузки.

Но делая множество итераций оптимизации кода, куда удобнее использовать более простой и быстрый инструмент и один конкретный тип запросов (а после оптимизации одного запроса изучать следующий, и т.д.). Мой выбор — wrk. Тем более что в моем случае количество роутов не велико — проверить все по одному не сложно.

Сразу надо оговорится, что в плане блокирующих запросов, ожидания БД и т.п. приложение уже оптимизировано, все упирается в cpu: при тестах воркер потребляет 100% cpu.

На продашен серверах используется node.js версии 6 — с неё и начнем:

Requests/sec: 1210

Пробуем на 8й ноде:
Requests/sec: 2308
10я нода:
Requests/sec: 2590

Разница очевидна. Ключевую роль тут играет обновление версии v8 — множество плохо оптимизирующегося v8 кода осталось в прошлом. И чтобы не бороться с ветряными мельницами исчезнувшими в node.js v8 — лучше сразу обновиться, а потом уже заниматься оптимизацией кода.

Переходим собственно к поиску узких мест: на мой взгляд, лучший инструмент для этого — flamegraph. И с появлением проекта 0x получить flamegraph стало очень просто — запускам 0x вместо node: 0x -o ваш_скрип.js, делаем тест, останавливаем скрипт, смотрим результат в браузере.

Примерно так выглядит flamegraph тестируемого кода до оптимизаций:


Внизу фильтры, оставляем app, deps — только код приложения и сторонних модулей.

Чем шире полоска — тем больше времени потрачено на выполнения этой функции (включая вложенные вызовы).

Разбираться будем с центральной, самой большой частью.

В первую очередь подсвечиваем неоптимизированные функции. У меня в приложении таких нашлось немного.

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

Дальше возможен простой алгогритм действий: оптимизировать самые широкие функции, переходя от одной к другой. Но я выбрал другой подход: оптимизировать начиная от точки входа в приложения (обработчик запроса в http.createServer). В конце исследуемой функции вместо вызова следующих функций я завершаю обработку запроса, отвечая ответом-пустышкой, и изучаю производительность именно этой функции. После её оптимизации ответ-пустышка перемещается дальше по стеку вызовов к следующей функции и т.д.

Удобное следствие такого подхода: можно видеть rps в идеальных условиях (при работающей только одной стартовой функцией rps близок к максимальному rps-у hellow world node.js приложения), и при дальнейшем перемещении заглушки-ответа вглубь приложения наблюдать вклад исследуемой функции в падение производительности в rps-ах.

Итак, оставляем только стартовую функцию, получаем:

Requests/sec: 16176

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

Переходим к следующей функции:

Requests/sec: 16111
Ничего не изменилось — погружаемся дальше:
Requests/sec: 13330

Наш клиент! Видно что задействованная функция getByUrl занимает значимую часть стартовой функции — что хорошо коррелирует с проседанием rps.

Смотрим внимательно что в ней происходит (включаем core, v8):

Много чего происходит… курим код, оптимизируем:

for (var i in this.data) {
  if (this[i]._options.regexp_obj.test(url)) return this[i];
}
return null;

превращаем в
let result = null;
for (let i=0; i<this.length && !result; i++) {
  if (this[i]._options.regexp_obj.test(url)) result = this[i];
}

В данном случае простой for значительно быстрее for..in

Получаем Requests/sec: 16015

Визуально функция «сдулась» и занимает значительно меньшую долю от стартовой функции.
В детальной информации по функции так же все значительно упростилось:

Идем дальше, к следующей функции

Requests/sec: 13316

В этой функции много array функций и, несмотря на существенное ускорение в последних версиях node.js, они все еще медленней простых циклов: меняем [].map и filter. на обычный for и получаем

Requests/sec: 15067

И так раз за разом, для каждой следующей функции.

Еще несколько пригодившихся оптимизаций: для хешей с динамически изменяемым набором ключей new Map() может быть на 40% быстрее обычного {};

Math.round(el*100)/100 в 2 раза быстрее чем toFixed(2).

В flamegraph-е для core и v8 функций можно увидеть как и малопонятные записи, так и вполне говорящие StringPrototypeSplit или v8::internal::Runtime_StringToNumber, и, если это значимая часть выполнения кода, попытаться оптимизировать, например просто переписать код, не выполняющий эти операции.

Например, замена split на несколько вызовов indexOf и substring может давать двойной выигрыш в производительности.

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

Тут может помочь вдумчивое изучение вывода node --trace_file_names --trace_opt_verbose --trace-deopt --trace_opt

Например, строчки вида

deoptimizing (DEOPT soft): begin 0x2bcf38b2d079 <JSFunction getTime… Insufficient type feedback for binary operation привели к строчке

return val >= 10? val: '0'+val;

Замена на

return (val >= 10? '': '0')+val;

исправила ситуацию.

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

github.com/P0lip/v8-deoptimize-reasons — список,
www.netguru.co/blog/tracing-patterns-hinder-performance — разбор типовых причин,
www.html5rocks.com/en/tutorials/speed/v8 — про оптимизации для v8, думаю справедливо и для текущего движка v8.

Но многие из проблем уже не актуальны для нового v8.

Так или иначе, после всех оптимизаций удалось получить Requests/sec: 9971, т.е. ускорится примерно в 2 раза за счет перехода на свежую версию node.js, и еще в 4 раза за счет оптимизации кода.

Надеюсь, этот опыт будет полезен кому-нибудь еще.

Оптимизация цикла JavaScript делает его медленнее

Начнем с того, что я не вижу причин, почему второй должен быть намного быстрее первого. Разница между сравнением с нулем и сравнением с другим числом-это то, что может иметь значение в чрезвычайно узких петлях в скомпилированном коде, но даже там это, вероятно, выбор культа карго большую часть времени (прочитайте науку о культе карго Ричарда Феймана, если вы не получите ссылку, если ничего другого, это хорошо читается, есть также несколько раз, когда подобные тенденции копируют что-то это хорошо сработало однажды в случае, когда нет реальной причины полагать, что это поможет в программировании).

Я мог видеть следующее медленнее:

for (i = 0; i < myarray.length; i++) {
// do something with myarray[i]
}

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

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

Помимо таких предположений, однако, мы не можем ничего сказать об этом за пределами "потому что один работает лучше в этом двигателе, чем другой, вот почему", не доходя до уровня ниже javascript и не изучая реализацию двигателя. Сами ваши результаты предполагают, что ответ не будет одинаковым с каждым двигателем (в конце концов, один из них больше соответствует тому, что вы ожидали).

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

Если вас интересует, стоило ли это когда-либо или было просто предположением, вы можете попытаться получить копию Netscape 2 (первый браузер javascript когда-либо, в конце концов) и запустить некоторый код, чтобы проверить подход к нему.

Edit: если вы попробуете такой эксперимент, другой - попробовать намеренно багги-циклы, которые превышают границы массива на один. Одна из возможных оптимизаций для движка-понять, что вы идете по массиву, и проверить один раз, где вы закончите для out-of-range. если это так, у вас могут быть разные результаты, если вы в конечном итоге ошибетесь.

Оптимизация JS и CSS кода сайта

Оптимизация JS

Всем-всем привет!

Продолжаем оптимизировать скорость загрузки сайта и сегодня на очереди у нас оптимизация JS (JavaScript) и CSS кода. Напомню, вчера мы работали с изображениями, если Вы все еще не оптимизировали их, то 105 урок как раз для Вас (обязательно примените то, что написано там).

Урок получится коротким, поэтому скорее начнем. Погнали!

Что такое JS и CSS код?

В настоящее время сайт, созданный исключительно на HTML и CSS, уже является отстающим, ведь на этих языках нельзя написать какие-то удобные, полезные штуки, которые облегчили бы взаимодействие с ним. Пользователям, в свою очередь, необходимо преподнести максимально удобный продукт (веб-ресурс). Осуществить данное требование помогут различные языки программирования, к которым относится и JavaScript.

JavaScript – язык программирования, позволяющий создавать различные скрипты (приложения), которые встраиваются в HTML-страницы. Скрипты выполняются в браузере пользователя.

Чтобы вывести даже тот самый пресловутый счетчик времени потребуется JS. Так что, думаю, и на Вашем сайте присутствует данный язык программирования.

CSS – язык описания внешнего вида любого элемента сайта. То есть то, как выглядит Ваш сайт, мой сайт, да любой другой, написано на этом языке.

Для чего нужно оптимизировать JS и CSS код?

Задача данного мероприятия одна – снизить время загрузки страниц сайта. К сожалению, JS-скрипты и CSS код зачастую несут в себе очень много символов, пробелов, чем и замедляют загрузку веб-ресурса. Оптимизация подобных файлов направлена на то, чтобы отсечь лишние символы, лишние пробелы, тем самым снижая их размер и, как следствие, облегчая загрузку веб-страниц. По сути происходит обычное сжатие файла. Можно сделать и более глубокую оптимизацию, если, конечно, Вы разбираетесь в программировании и сайтостроении.

Оптимизация JS и CSS кода

В Интернете, как и в случае с оптимизацией изображений, существует несколько онлайн-сервисов, которые выполняют то, что написано выше:

  1. JSCompress. Работает исключительно с JavaScript;Оптимизация JS онлайн
  2. Refresh-SF. Позволяет оптимизировать как JS, так и CSS, а также работает с HTML.Оптимизация js

Ваша задача: скопировать код файла, вставить его в один из перечисленных сервисов, получить оптимизированный код и вставить его в исходный файл. Вот и все.

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

Оптимизируя свой блог, я попробовал оба сервиса: в первый залил проблемный файл JS, а во второй CSS (как узнать проблемные файлы?) и буквально через 5 секунд код оптимизировался и уже можно было заливать, что я и сделал.

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

На этом все, дорогие друзья!

До скорых встреч!

Добавить комментарий

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