Web со скоростью клика
Оптимизация загрузки
Чтобы сайт загружался быстро существует несколько простых способов, которые к тому же не сложно применить на практике. Конечно все зависит от вашего проекта, его размеров и особенностей. Но все же большинство правил применимо везде.
Основные принципы:
- Делать меньше HTTP запросов к серверу
- CSS файлы подключаем в head
- Скрипты загружаем перед </body> и перед счетчиками и дургими внешними "медленными" или непрогнозируемыми вещами
- Убираем inline стили, блоки кода с HTML шаблонов. Все грузим с кешируемых внешних файлов.
- Переносим файлы CSS JavaScript графику на cookie-free домен
- Избегаем CSS Expressions
- Expires заголовки, настраиваем нужное кеширование
- GZIP для HTML CSS JavaScript файлов
- Уменьшаем кол-во используемых DNS имен
- Сжимаем HTML CSS JavaScript
- Избегаем редиректов
Я выделяю три состояния загруженности страницы:
- Читабельный текст - time-to-text
- загружен DOM, можем отпработать JavaScript
- Полная загрузка
Предзагрузка
Когда мы можем догадаться о следующих действиях пользователя (переход на соседнюю старницу в пейджере, ссылка на следующее фото и тд) выгодно загрузить эти данные не дожидаясь клика пользователя. И при клике он уже увидит все моментально.
Данные можно грузить как до DOM-load так и после. Я бы предпочел грузить после если они не влияют на работоспособность скриптов. А в скриптах учитывать факт загрузки данных, чтобы не формировать лишние AJAX запросы. Можно отлавливать действия пользователя ивентами onmouseover, onmousedown и тд.
Фактически мы можем нагрузить кучу данных которые просто никогда не покажуться и все это выйдет бессмысленно. Нужно искать баланс.
Одна из возможных ошибок при предзагрузке - то что если в HTML указаны элемеенты IMG, EMBED< OBJECT и тд - то файлы будут грузиться независимо от свойства display и visible.
Постзагрузка
Вообще часть данных можно смело перенести на пост-загрузку. Это когда уже произошло событие DOM=load, у нас еще догружаются картинки в своей очереди.
В пост загрузку эффективно отправлять медленные мало-важные для нас скрипты, счётчики, дополнительный функционал которым редко пользуются пользователи.
Например, всегда старался подключать банера только после DOM-load (обговорено, не втихаря). Тогда пользователь ждущий появление текста на экране - увидит текст а не банер на пол экрана net-бука с 3G модемом и помегобайтной оплатой :)
Инструменты для оптимизации:
Google Chrome:- Speed Tracer
- Firebug/Net
- Yahoo! YSlow
- Inline Code Finder
- Page speed
- AOL Pagetest
Как работает рендеринг
Кроме быстрой загрузки и показа первой страницы, сайт еще должен быстро реагировать на действия пользователя. Опять может получиться что значительное время web интерфейс тормозит в браузере а не на сервере. Рассмотрим как происходит рендер вставляемой в документ информации.
Content tree - модель документа в представлении браузера, подобна DOM, но есть некоторые отличия.
Фрейм - атомная единицп Content tree - тоже что и node в DOM
Computed styles - расчитанные стили отображения фрейма
Браузер скачивает HTML, по ходу скачивания парсит его и начинает строить content tree, иногда выполняя paint готовых блоков. При наличии загруженных стилей они учитываются при построении фреймов.

DOM дерево

Content tree
Content tree - тот же DOM но без head блока. Так же туда не попадают все HTML node которые имеют стиль
display:none. Текст представляется в виде фремов - по фрейму на каждую строку текста.
Если попадается <script type="text/javascript"> то пока он скачивается и парситься блокируется дальнейшее
построение Content tree,
так как script может содержать операции по изменению контента (например, document.write).

процесс рендеринра web-страницы
Последовательно для каждого фрейма перебираются селекторы из CSS, чтобы высчитать computed styles.
Соответственно при большом количестве тегов в HTML и/или большом количестве селекторов CSS производиться
много проверок. Каждый селектор CSS должен быть проверен на соответствие проверяемому фрейму.
Мы должны по возможности избавляться от лишних тегов при написании HTML, также важно соблюдать как можно
меньшую вложенность тегов друг в друга. Больше особо мы сделать ничего тут не можем, поэтому лучше обратить
внимание на CSS.
Оптимизация CSS
Самая большая проблема для производительности это количество используемых селекторов. Но нам же нужно как-то
стилизировать HTML? В любом случае оптимизация не должна мешать разработке, и не стоит оптимизировать на
ровном месте. Так как сайты зачастую содержат в себе больше 1 стараницы, и практически всегда страницы
настолько похожи
что мы используем один CSS файл для всех страниц сайта. Это хорошо - так как файл кешиться и при переходе по
старницам меньше
информации уже нужно для загрузки. Но это большой минус для скорости рендеринга, так как появляется куча
селекторов никак не используемых в
текущем HTML коде. Они всеравно участвуют при переборе селекторов
при reflow.
Перебор занимает время, больше перебирать - дольше перебирается.

Обход селекторов
Как это работает:
Браузер (как минимум Mozilla Firefox) строит для ускорения хеш-таблицы с элементами. Существует две таблицы - для элментов с классом и для элементов с id.
Обычно id меньше чем классов на страницах, и id может быть лишь один, поэтому элементы по id будут быстрее находиться. Тоесть тут не полная аналогия с JavaScript.
#block - найдёт элемент с id block
div#block - найдёт элемент с id block
.item - найдёт все элементы с классом item
div - найдеёт все дивы из дерева, не особо быстро при большом CSS но мы же хотели все div-ы
div > p - обходя по дереву будет искать сначала p, как только найдёт p, будет проверять его непосредственного предка не div ли это.
div p - все также только будет проверять всех его предков пока не дойдёт до div или вершины.
body > div p - опять также, но div должен иметь предка body.
div * - обойдет все элементы, от каждого поднимаясь вверх по дереву чтобы выяснить если ли у него div в предках
Таким образом прослеживается ситуация с производительностью. Если мы недостаточно конкретизируем ключевой-селектор (последний, тот что справа) то теряем в производительности, из-за большего количества проверок.
Пример обычного кода:
Так я обычно пишу стили для какого-то блока. Если внутри указывается Id или class для тега, то он получает приставку "b-item" - название по смыслу блока.
Так может выглядеть ускоренный вариант:
И стили, используются только className и каскадирование в случае если такой className нам очень хочется пере-использовать внутри этого блока.
Еще раз напишу. Оптимизация должна быть только там где требуется и это не нарушает поддержки и читабельности кода!
В первую очередь оптимизируются самые критичные места - то где наибольшее количество вызовов, например списки ul li, ссылки, параграффы. Если блок всего один раз на странице, то скорее всего смысла его ускорять никакого нет.
Почему плохи CSS внутри HTML документа, зачем их выносить в head. Каждый раз когда браузер встречает новые правила, ему нужно их скомпоновать с уже накопленными. Затем уже отрисованную часть старницы необходимо пересчитать и перерисовать так как просто она уже могла устареть.
Оптимизация Javascript
Javascript может непосредственно менять CSS стили как отдельных элементов DOM дерева, так и добавлять CSS стили через header документа. Также javascript-ом мы манипулируем над контентом старницы, тоесть перестраиваем DOM и content tree. Любое из этих действий может повлечь за собой reflow и/или repaint.
Способы поменьше вызывать reflow:
Ограничиться как можно меньшим влиянием н DOM. Как это лучше сделать. Накапливать нужную информацию для вставки в DOM в како либо обьекте и потом уже добавлять сам обьект.
Формировать HTML в javascript шаблонах и потом заменять контент старой или новой ноды с помощью innerHTML.
При работе со стилями поменьше использовать код вида
Лучше это делать просто сменой класса элементу, а представление описать в CSS файле стилей. Это и разделение контента и защищает от лавины reflow при последовательных применениях стилей.
Пореже опрашивать свойства элеентов которые зависят от вычисляемых стилей. Так как браузер пытается избежать водопада reflow и собирает их в паки для обработки за раз. А любое обращение к вычисленным стилям генерирует немедленный reflow, чтобы пересчитать эти стили и отдать актуальную информацию.
Пишите raw-JavaScript код там где это выгодно. JavaScript библиотеки самми на нём написаны :)
Если много данных меняется в каком-то отдельном блоке, и водопада никак не избежать, есть одна техника.
Просто перед работой с контентом блока, скройте его. Ставьте display none, только контейнеру блока. Больше
ничего не
потребуется. Так как он выпал из content tree то больше он не учитывается при reflow и изменения контента
этого блока через DOM
никак не спровозируют reflow и repaint.
Главный минус этого подхода - блок будет моргать. Настолько сильно насколько долго будут производиться
манипуляции над DOM. Зато мы получим всего 2 reflow и 1 repaint. Сколько б операций над контентом не
производили.
Регулярно обновляйте javascript-framework, так как с каждой новой версией все больше шанс что разработчики уделят внимание оптимизации старых фичей.
CSS3
Чем нам поможет CSS3?
CSS3
Этот элемент не содержит картинок, просто CSS3
Чтиво
Книги
- Николай Мациевский / Евгений Степанищев / Глеб Кондратенко. Реактивные веб-сайты
- Николай Мациевский. Разгони свой сайт
- Steve Soulders. High Preformance Web Sites (O'Reilly)
Рендеринг
- Faster HTML and CSS: Layout Engine Internals for Web Developers
- Understanding Internet Explorer Rendering Behaviour Performance, Scalability and Architecture
- Rendering: repaint, reflow/relayout, restyle
- Notes on HTML Reflow
- Визуализация reflow / Gecko / Хабрахабр
- Taming CSS Selectors
- How to Write Efficient CSS Selectors - O'Reilly Answers
- Writing Efficient CSS for use in the Mozilla UI - MDC
- The Cascade, Grids, Headings, and Selectors from an OOCSS Perspective, Ajax Experience 2009
- High Performance Web Sites :: Performance Impact of CSS Selectors
- YouTube - Faster HTML and CSS: Layout Engine Internals for Web Developers
- Flying Images
- http://www.spritely.net/gallery/
Загрузка
- Оптимизация времени загрузки сайтов
- Let's make the web faster
- Lazy Load Plugin for jQuery
- MHTML - when you need data: URIs in IE7 and under
- 43 In-Browser Web Development Tools That Will Make You A Better Web Developer
- HTML5: HIGH-PERFORMANCE BEST PRACTICES FOR WEB SITES
Javascript
- Sizzle JavaScript Selector Library
- MIX2010 video - HOW JQUERY MAKES HARD THINGS SIMPLE
- Простое шаблонирование в JavaScript
- Блог wtfjs
- Paul Sweatte - JavaScript Optimization
- Best Practices for Speeding Up jQuery
- Efficient JavaScript - Opera Developer Community
- IEBlog : IE + JavaScript Performance Recommendations - Part 1
- Part 2: JavaScript Code Inefficiencies
- Part 3: JavaScript Code Inefficiencies