предисловие
В эпоху мобильного интернета у пользователей все выше требования к скорости открытия веб-страниц. Исследование, проведенное отделом пользовательского опыта Baidu, показывает, что взаимосвязь между процентом отказов от страниц и временем открытия страниц показана на рисунке ниже.
Согласно результатам исследования отдела пользовательского опыта Baidu, средний пользователь ожидает и может принять время загрузки страницы в течение 3 секунд. Если время загрузки страницы слишком медленное, пользователь потеряет терпение и решит уйти.
Как первый экран, обращенный к пользователю, важность первого экрана очевидна. Оптимизация взаимодействия с пользователем — это одна из вещей, на которых мы должны сосредоточиться во фронтенд-разработке.
В этой статье мы используем 8 вопросов для интервью, чтобы рассказать о процессе рендеринга в браузере и оптимизации производительности.
Сначала мы ответим на эти 8 вопросов, чтобы понять процесс рендеринга в браузере, а решение будет дано позже~
Почему Javascript однопоточный?
Почему JS блокирует загрузку страницы?
Будет ли загрузка css вызывать блокировку?
В чем разница между DOMContentLoaded и load?
Что такое CRP (Critical Rendering Path) и как его оптимизировать?
Разница между отсрочкой и асинхронностью?
Говорите о переформатировании браузера и перерисовке?
Что такое слияние слоев рендеринга (Composite)?
Процесс и поток
Процесс (process) и поток (thread) — основные понятия операционной системы.
Процесс — это наименьшая единица распределения ресурсов ЦП (наименьшая единица, которая может владеть ресурсами и работать независимо).
Поток — это наименьшая единица планирования ЦП (единица выполнения программы, основанная на процессе).
Современные операционные системы могут выполнять несколько задач одновременно, например, использовать браузер для работы в Интернете и одновременно слушать музыку.
Для операционной системы задача — это процесс., Например, открытие браузера запускает процесс браузера, а открытие Word запускает процесс Word.
Некоторые процессы выполняют несколько действий одновременно, например Word, который может выполнять набор текста, проверку орфографии, печать и т. д. одновременно.В процессе, чтобы делать несколько вещей одновременно, вам нужно одновременно запускать несколько «подзадач». Мы называем эти «подзадачи» в процессе потоками..
Поскольку каждый процесс выполняет по крайней мере одно действие, у процесса есть по крайней мере один поток. Система будет выделять независимую память каждому процессу, поэтому у процесса есть свои независимые ресурсы. Пространство памяти процесса (включая сегменты кода, наборы данных, кучи и т. д.) совместно используется потоками одного и того же процесса.
Если использовать яркую метафору, процесс подобен граничному производственному заводу, а нить — работнику на заводе, который может заниматься своими делами или сотрудничать друг с другом для выполнения одного и того же.
Когда мы запускаем приложение, компьютер создаст процесс, операционная система выделит часть памяти под процесс, и все состояние приложения будет храниться в этой памяти.
Приложение также может создавать несколько потоков для помощи в работе, и эти потоки могут совместно использовать данные в этой части памяти. Если приложение закрыто, процесс будет завершен, и операционная система освободит соответствующую память.
Многопроцессорная архитектура браузера
Хорошая программа часто делится на несколько модулей, которые независимы и взаимодействуют друг с другом, и то же самое верно для браузеров.
Взяв, к примеру, Chrome, он состоит из нескольких процессов, у каждого из которых есть свои основные обязанности, и они взаимодействуют друг с другом для выполнения общей функции браузера.
Каждый процесс содержит несколько потоков, и несколько потоков в процессе будут работать вместе для выполнения обязанностей процесса.
Chrome использует архитектуру с несколькими процессами, и на верхнем уровне есть процесс браузера для координации других процессов браузера.
преимущество
Поскольку по умолчанию открывается новая вкладка и создается новый процесс, сбой одной вкладки не повлияет на весь браузер.
Точно так же сбои сторонних плагинов не повлияют на весь браузер.
Многопроцессорность позволяет в полной мере использовать преимущества нескольких ядер современных процессоров.
Модель песочницы удобно использовать для изоляции таких процессов, как плагины, и повышения стабильности браузера.
недостаток
Система выделяет ресурсы, такие как память и ЦП, для вновь открытого процесса браузера, поэтому потребление ресурсов памяти и ЦП также будет больше.
Тем не менее, Chrome проделал хорошую работу по освобождению памяти, и основная память может быть быстро освобождена для запуска других программ.
Основные процессы и обязанности браузера
Основной процесс Браузерный процесс
Отвечает за отображение и взаимодействие интерфейса браузера. Управление отдельными страницами, создание и уничтожение других процессов. Управление сетевыми ресурсами, загрузка и т. д.
Процесс подключаемого модуля стороннего производителя Процесс подключаемого модуля
Каждый тип подключаемого модуля соответствует процессу, который создается только при использовании подключаемого модуля.
Процесс графического процессора Процесс графического процессора
Максимум один, для 3D-рисования и т. д.
Процесс визуализации
Вызывается процессом рендеринга браузера или ядром браузера, он является многопоточным внутри. В основном отвечает за рендеринг страницы, выполнение скриптов, обработку событий и т. д. (Эта статья посвящена анализу)
процесс рендеринга (ядро браузера)
Процесс рендеринга в браузере многопоточный, давайте посмотрим, какие у него основные потоки:
1. Поток рендеринга графического интерфейса
Отвечает за рендеринг интерфейса браузера, синтаксический анализ HTML, CSS, построение дерева DOM и дерева RenderObject, компоновку и рисование и т. д.
Когда интерфейс нужно перерисовать (Repaint) или вызвать какую-то операцию перерисовки (reflow), будет выполнен поток.
Обратите внимание, что поток рендеринга графического интерфейса пользователя и поток механизма JS являются взаимоисключающими.При выполнении механизма JS поток графического интерфейса будет приостановлен (эквивалентно замораживанию), а обновления графического интерфейса будут сохранены в очереди и выполнены сразу же после запуска механизма JS. простаивает. .
2. Поток движка JS
Механизм Javascript, также известный как ядро JS, отвечает за обработку сценариев Javascript. (например, двигатель V8)
Поток движка JS отвечает за синтаксический анализ сценариев Javascript и выполнение кода.
Движок JS ожидает поступления задач в очередь задач, а затем обрабатывает их.В любой момент существует только один поток JS, выполняющий программу JS на вкладке (процесс рендеринга).
Обратите внимание, что поток рендеринга GUI и поток движка JS являются взаимоисключающими, поэтому, если время выполнения JS слишком велико, это приведет к тому, что рендеринг страницы будет несогласованным, а рендеринг и загрузка страницы будут заблокированы.
3. Поток триггера события
Он принадлежит браузеру, а не движку JS, и используется для управления циклом событий (понятно, что движок JS слишком занят сам по себе, и браузеру нужно открыть другой поток, чтобы помочь)
Когда движок JS выполняет блоки кода, такие как setTimeOut (или другие потоки из ядра браузера, такие как щелчки мышью, асинхронные запросы AJAX и т. д.), соответствующие задачи будут добавлены в поток событий.
Когда соответствующее событие соответствует условиям запуска и срабатывает, поток добавит событие в конец очереди ожидания и будет ждать, пока механизм JS обработает его.
Обратите внимание, что из-за однопоточной связи JS события в этих ожидающих очередях должны быть поставлены в очередь для обработки механизмом JS (который будет выполняться только тогда, когда механизм JS простаивает).
4. Временная триггерная нить
Поток, в котором находятся легендарные setInterval и setTimeout
Счетчик времени браузера не учитывается механизмом JavaScript (поскольку механизм JavaScript является однопоточным, если он находится в состоянии заблокированного потока, это повлияет на точность времени)
Таким образом, время замеряется и запускается отдельным потоком (после того, как время завершено, оно добавляется в очередь событий и выполняется после ожидания простоя JS-движка).
Обратите внимание, что W3C предусматривает в стандарте HTML, что временной интервал ниже 4 мс в setTimeout должен считаться 4 мс.
5. Асинхронный поток HTTP-запросов
После подключения XMLHttpRequest в браузере открывается новый запрос потока.
При обнаружении изменения состояния, если установлена функция обратного вызова, асинхронный поток сгенерирует событие изменения состояния и поместит обратный вызов в очередь событий. А затем выполняется движком JavaScript.
Процесс рендеринга в браузере
Если вы хотите рассказать о том, что происходит от ввода URL до загрузки страницы, это будет бесконечно... Здесь мы говорим только о процессе рендеринга браузера.
Парсинг HTML-файлов, построение DOM-дерева, а за загрузку CSS-файлов отвечает основной процесс браузера.
Файл CSS загружается, анализируется файл CSS в виде древовидной структуры данных, а затем объединяется дерево DOM в дерево RenderObject.
Макет дерева RenderObject (Layout/reflow), отвечающий за расчет размера и положения элементов в дереве RenderObject
Нарисуйте дерево RenderObject (рисуйте), нарисуйте информацию о пикселях страницы
Основной процесс браузера передает слои по умолчанию и составные слои процессу графического процессора, а затем процесс графического процессора компонует каждый слой и, наконец, отображает страницу.
отвечать
1. Почему Javascript однопоточный?
Это из-за миссии Javascript, родившегося языка сценариев!Javascript используется для обработки взаимодействия с пользователем на странице, а также для управления деревом DOM и деревом стилей CSS, чтобы предоставить пользователям динамичный и богатый интерактивный опыт и интерактивную обработку сервера. логика.
Если JavaScript является многопоточным для управления этими DOM пользовательского интерфейса, могут возникнуть конфликты манипулирования пользовательским интерфейсом.
Если Javascript является многопоточным, при многопоточном взаимодействии узел DOM в пользовательском интерфейсе может стать критическим ресурсом,
Если предположить, что с DOM одновременно работают два потока, один из которых отвечает за изменение, а другой — за удаление, то в это время браузеру необходимо решить, как воздействовать на результат выполнения того или иного потока.
Конечно, мы можем решить вышеуказанные проблемы с помощью замков. Но чтобы избежать большей сложности из-за введения блокировок, Javascript с самого начала выбрал однопоточное выполнение.
2. Почему JS блокирует загрузку страницы?
Поскольку JavaScript может манипулировать DOM, если интерфейс визуализируется при изменении этих свойств элемента (то есть поток JavaScript и поток пользовательского интерфейса выполняются одновременно), данные элемента, полученные до и после потока визуализации, могут быть несогласованными.
Поэтому, чтобы предотвратить непредсказуемые результаты рендеринга, настройки браузераПоток рендеринга GUI и механизм JavaScript являются взаимоисключающими.Отношение.
Поток графического интерфейса пользователя приостанавливается на время выполнения механизма JavaScript, а обновления графического интерфейса хранятся в очереди и выполняются, как только поток механизма простаивает.
Из вышесказанного мы можем сделать вывод, что, поскольку поток рендеринга GUI и поток выполнения JavaScript являются взаимоисключающими,
Когда браузер выполняет программу JavaScript, поток рендеринга GUI будет сохранен в очереди и не будет продолжаться, пока выполнение программы JS не будет завершено.
Поэтому, если время выполнения JS слишком велико, это приведет к непоследовательности рендеринга страницы, что приведет к ощущению рендеринга страницы и блокировки загрузки.
3. Будет ли загрузка css вызывать блокировку?
Из приведенного выше процесса рендеринга браузера мы видим:
DOM и CSSOM обычно строятся параллельно, поэтомуЗагрузка CSS не блокирует синтаксический анализ DOM.
Однако, поскольку дерево рендеринга зависит от дерева DOM и дерева CSSOM,
Поэтому он должен дождаться, пока дерево CSSOM будет построено, то есть после того, как ресурс CSS будет загружен (или ресурс CSS не загрузится), прежде чем он сможет начать рендеринг.
следовательно,Загрузка CSS блокирует рендеринг Dom.
Поскольку JavaScript может манипулировать стилями DOM и CSS, если интерфейс визуализируется при изменении этих свойств элемента (то есть поток JavaScript и поток пользовательского интерфейса выполняются одновременно), данные элемента, полученные до и после потока визуализации, могут быть непоследовательный.
Поэтому, чтобы предотвратить непредсказуемые результаты рендеринга, настройки браузераПоток рендеринга GUI и механизм JavaScript являются взаимоисключающими.Отношение.
Следовательно, таблица стилей будет загружена и выполнена до того, как будут выполнены последующие js, поэтомуcss заблокирует выполнение последующих js.
4. В чем разница между DOMContentLoaded и load ?
Когда событие DOMContentLoaded запускается, только после завершения синтаксического анализа DOM, за исключением таблиц стилей и изображений. мы упоминали ранееЗагрузка CSS заблокирует рендеринг Dom и выполнение следующих js, что заблокирует синтаксический анализ Dom., поэтому мы можем сделать вывод:
Если в документе нет скрипта, браузер может инициировать событие DOMContentLoaded после синтаксического анализа документа. Если документ содержит сценарий, сценарий блокирует синтаксический анализ документа, и перед выполнением сценария необходимо дождаться сборки CSSOM. В любом случае для срабатывания DOMContentLoaded не требуется ждать загрузки других ресурсов, таких как изображения.Когда запускается событие onload, все DOM, таблицы стилей, скрипты, изображения и другие ресурсы на странице уже загружены.
DOMContentLoaded -> загрузить.
5. Что такое CRP (Critical Rendering Path) и как его оптимизировать?
Критический путь рендеринга — это последовательность шагов, которые браузер выполняет для преобразования HTML, CSS и JavaScript в пиксельный контент, отображаемый на экране. То есть процесс рендеринга в браузере, о котором мы упоминали выше.
Чтобы получить первый рендер как можно быстрее, нам нужно минимизировать следующие три переменные:
Количество критических ресурсов: ресурсы, которые могут помешать отображению страницы в первый раз.
Длина критического пути: количество циклов или общее время, необходимое для получения всех критических ресурсов.
Критические байты: общее количество байтов, необходимое для первого рендеринга веб-страницы, равное сумме размеров файлов всех критических передач ресурсов.
1. Оптимизируйте DOM
Удалите ненужный код и комментарии, включая пробелы, и постарайтесь сделать файл как можно меньше.
Файлы можно сжимать с помощью GZIP.
В сочетании с файлами кеша HTTP.
2. Оптимизируйте CSSOM
Минификация, сжатие и кэширование одинаково важны дляCSSOMРанее мы отмечали, что этопредотвратить рендеринг страницы, поэтому мы можем рассмотреть возможность оптимизации с этой точки зрения.
Уменьшите количество критических элементов CSS
Когда мы объявляем таблицы стилей, обратите пристальное внимание на типы медиа-запросов, которые сильно влияют на производительность CRP.
3. Оптимизируйте JavaScript
Когда браузер встречает тег скрипта, онЗапретить работу синтаксического анализатора до тех пор, пока не будет построена CSSOM., JavaScript запустится и продолжит процесс построения DOM.
async: Когда мы добавим атрибут async к тегу script, браузер продолжит анализировать DOM, когда встретит тег script, и скрипт не будет заблокирован CSSOM, то есть CRP не будет заблокирован.
отсрочка: разница с асинхронным режимом заключается в том, что скрипт должен ждать, пока документ не будет проанализирован (до события DOMContentLoaded), чтобы выполниться, в то время как асинхронный позволяет скрипту работать в фоновом режиме, пока документ анализируется (процесс загрузки двух будет не блокировать DOM, но выполнение будет).
async рекомендуется, когда наш скрипт не будет изменять DOM или CSSOM.
Предварительная загрузка — предварительная загрузка и предварительная выборка.
Предварительное разрешение DNS — dns-prefetch.
Суммировать
Анализируйте и используйтеКоличество критических ресурсов Количество критических байт Длина критического путичтобы описать наш CRP.
Сведите к минимуму количество критических ресурсов: устраните их (inline), отложите их загрузку (defer) или сделайте так, чтобы они разрешались асинхронно (async) и т. д.
Оптимизируйте ключевые байты (минификация, сжатие), чтобы сократить время загрузки.
Оптимизируйте порядок загрузки оставшихся критически важных ресурсов: разрешите загрузку критических ресурсов (CSS) раньше, чтобы сократить длину CRP.
Оптимизация производительности внешнего интерфейса Оптимизация рендеринга критического пути
6. В чем разница между отсрочкой и асинхронностью?
Когда браузер встречает скрипт script:
1. <script src="script.js">
Без отсрочки или асинхронности браузер загрузит и выполнит указанный скрипт немедленно. «Немедленно» означает до рендеринга элемента документа под тегом script, то есть он не ждет последующего загруженного элемента документа и загружает его, когда он читается и выполняется.
2. <script async src="script.js">
При использовании асинхронности процесс загрузки и рендеринга последующих элементов документа будет происходить параллельно (асинхронно) с загрузкой и выполнением script.js.
3. <script defer src="myscript.js">
С defer процесс загрузки последующих элементов документа будет выполняться параллельно (асинхронно) с загрузкой script.js, но выполнение script.js должно быть завершено после парсинга всех элементов и до запуска события DOMContentLoaded.
С практической точки зрения, лучше всего сначала генерировать все скрипты перед