Статья, чтобы понять, как работает браузер Chrome

Chrome
Статья, чтобы понять, как работает браузер Chrome

предисловие

Эта статья принадлежит авторуMario Kosakaнаписаноinside look at modern web browserПеревод цикла статей. Перевод здесь относится не к дословному переводу, а к выражению того, что автор хочет выразить, исходя из личного понимания, и постарается добавить соответствующий контент, чтобы помочь всем лучше понять.

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

CPU, GPU, память и многопроцессорная архитектура

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

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

Сердце компьютера - CPU и GPU

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

CPU

Первое, о чем мы хотим поговорить, это мозг компьютера — ЦП (Central Processing Uнит). Процессор — это микросхема компьютера с одним или несколькими ядрами. Мы можем сравнить ядро ​​​​процессора с офисным работником, онМощныйЗнающий астрономию и географию на дне, и всемогущий в живописи и каллиграфии,Он может обрабатывать поставленные перед ним задачи одну за другой последовательно. Давным-давно у большинства ЦП было только одно ядро, но в современных аппаратных устройствах ЦП обычно имеют несколько ядер, потому что многоядерные ЦП могут значительно повысить вычислительную мощность мобильных телефонов и компьютеров.

Четыре ядра ЦП с радостью выполняют задачи, переданные им на соответствующих станциях, одно за другим.

GPU

Графический процессор - или GPU (Graphics Processing Unit) — еще одна важная часть компьютера. В отличие от мощного ядра ЦП, одно ядро ​​графического процессора может справиться только с некоторыми простыми задачами, но это лучше, чем большое количество.На одном графическом процессоре будет много-много ядер, которые могут работать одновременно, что означает егоПараллельная вычислительная мощность очень сильнаиз. Графический процессор (GPU), как следует из названия, изначально использовался для обработки графики, поэтому когда дело доходит до графикиИспользовать графический процессор(используя) илиПоддержка графического процессора(поддерживается), люди связывают понятия, связанные с быстрым рендерингом графики или плавным взаимодействием с пользователем. В последние годы сКонцепция ускорения графического процессораПопулярность вычислений также стала все больше и больше выполняться только на графическом процессоре.

В каждом ядре GPU всего один ключ, а значит, его возможности очень ограничены, а их так много!

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

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

Выполнение программ в процессах и потоках

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

Процесс похож на большой аквариум, а нить — это рыба, плавающая в ванне.

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

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

Иногда для удовлетворения потребностей функции созданный процесс будет просить систему создать другие процессы для выполнения других задач, но вновь созданный процесс будет иметьНовое независимое пространство памятиВместо совместного использования памяти с исходным процессом. Если этим процессам необходимо взаимодействовать, они передаютIPCмеханизм (межпроцессное взаимодействие). Многие приложения примут этомультипроцессРаботать, потому что процессы и процессы независимы друг от друга, они не влияют друг на друга, иными словами, если один из рабочих процессов (worker process) зависнет, другие процессы не пострадают, а зависший процесс все равно может быть перезагрузка.

Различные процессы взаимодействуют через IPC

архитектура браузера

Так как же браузеры используют процессы и потоки для работы? Фактически его можно условно разделить на две архитектуры: одна — однопроцессная, то есть запускается только один процесс, а потоков в этом процессе несколько. Во-вторых, многопроцессорная архитектура: браузер запускает несколько процессов, каждый процесс имеет несколько потоков, и разные процессы взаимодействуют через IPC.

Схема архитектуры браузеров с одним и несколькими процессами

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

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

На диаграмме многопроцессорной архитектуры Chrome карта нескольких процессов рендеринга (процесс рендеринга) используется для указания того, что Chrome создаст процесс рендеринга для каждой вкладки.

Браузер Chrome будет иметь процесс браузера (browser process), который будет взаимодействовать с другими процессами для реализации функций браузера. Для процесса рендеринга (процесса рендеринга) Chrome попытается выделить отдельный процесс для каждой вкладки и даже каждого iframe на странице.

Как различные процессы работают вместе?

Ниже приводится конкретное рабочее содержание каждого процесса:

обработать ответственная работа
Browser Отвечает за «хромированную» часть браузера, включая панель навигации, закладки, кнопки «вперед» и «назад». В то же время этот процесс также контролирует те части, которые мы не можем видеть, включая отправку сетевых запросов и чтение и запись файлов.
Renderer Отвечает за всю работу, связанную с отображением вкладок и веб-страниц.
Plugin Управляет всеми плагинами, используемыми веб-страницами, такими как флеш-плагины.
GPU Отвечает за задачи графического процессора независимо от других процессов. Причина, по которой он независим как процесс, заключается в том, что ему необходимо обрабатывать запросы на рендеринг с разных вкладок и рисовать их в одном и том же интерфейсе.

За содержимое интерфейса разных частей браузера отвечают разные процессы.

В дополнение к процессам, перечисленным выше, в Chrome работает много других процессов, таких как процесс расширения и процесс утилиты. Если вы хотите увидеть, сколько процессов запущено в вашем браузере Chrome, вы можете нажать кнопку «Дополнительно» в правом верхнем углу браузера и выбрать «Дополнительные инструменты и диспетчер задач»:

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

Преимущества многопроцессорной архитектуры Chrome

Так почему же Chrome работает с многопроцессорной архитектурой?

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

На разных вкладках будут разные процессы рендеринга, за которые они будут отвечать.

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

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

Экономьте больше памяти — Обслуживание Chrome

Те же метод оптимизации также может быть использован в процессе браузера (процесс браузера). Архитектура браузера Chrome подвергается некоторым изменениям. Цель состоит в том, чтобы разделить части, связанные с самим браузером (Chrome) в разные сервисы. После службы эти функции могут работать в разных процессах или объединены. Запустить как отдельный процесс.

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

Разница между Chrome, выполняющим службы, связанные с браузером, в одном и том же процессе и в разных процессах

Процесс рендеринга одного кадра — изоляция площадки

Изоляция сайта(Изоляция сайта) — это функция, недавно запущенная в браузере Chrome, которая назначает отдельный процесс рендеринга для iframe разных сайтов на веб-сайте. Я уже говорил, что Chrome будет выделять отдельный процесс рендеринга для каждой вкладки, но если вкладка имеет только один процесс, то в этом процессе будут запускаться iframe разных сайтов, а это также означает, что они будут разделять память, что может привести к разрушениюТа же политика происхождения. Политика того же происхождения — это основная модель безопасности браузеров. Она может запретить веб-сайту получать данные с другого сайта без согласия, поэтому обход политики того же происхождения является основной целью многих атак безопасности. Изоляция процессов — лучший и самый эффективный способ изолировать веб-сайт. плюс наличие процессораРасплав и ПризракСкрытые опасности изоляции веб-сайтов стали обязательными. Таким образом, после версии Chrome 67 настольная версия Chrome будет включать изоляцию сайта по умолчанию, так что каждый межсайтовый iframe будет иметь независимый процесс рендеринга.

Функция изоляции сайта позволит межсайтовым фреймам иметь независимые процессы.

Технология изоляции веб-сайтов объединила усилия наших инженеров в области исследований и разработок в течение нескольких лет и на самом деле далеко не так проста, как выделение независимого процесса рендеринга для iframe разных сайтов, потому что принципиально меняет способ связи между каждым iframe. После того, как веб-сайт изолирован, для веб-сайтов с iframes, когда пользователь открывает инструмент разработчика справа, браузер Chrome фактически должен выполнять много скрытой работы, чтобы разработчик не мог почувствовать разницу с предыдущим один, который на самом деле трудно достичь. Для некоторых очень простых функций, таких как поиск по ключевому слову на странице с помощью клавиш Ctrl + F в devtool, Chrome должен выполнить несколько процессов рендеринга. Поэтому наши разработчики браузеров сетовали на то, что это было важным достижением после выпуска изоляции веб-сайтов.

что происходит при навигации

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

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

Все начинается с процесса браузера

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

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

Одна простая навигация

Шаг 1. Обработайте ввод

Когда пользователь начинает вводить текст на панели навигации, первое, что делает поток пользовательского интерфейса, — это спрашивает: «Введенная вами строка — поисковый запрос или URL-адрес?». Поскольку для браузера Chrome входными данными на панели навигации могут быть либо имя домена, которое можно запросить напрямую, либо информация о ключевом слове, которую пользователь хочет найти в поисковой системе (например, Google), поэтому, когда пользователь вводит информацию в Панель навигации Поток пользовательского интерфейса выполняет серию синтаксических анализов, чтобы определить, следует ли отправлять пользовательский ввод в поисковую систему или напрямую запрашивать введенные вами ресурсы сайта.

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

Шаг 2: Запустите навигацию

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

Поток пользовательского интерфейса сообщает веб-потоку перейти на mysite.com

В этот момент, если сетевой поток получает от сервера ответ перенаправления HTTP 301, он сообщит потоку пользовательского интерфейса о перенаправлении и снова сделает новый сетевой запрос.

Шаг 3: Прочитайте ответ

Когда сетевой поток получает поток тела (полезной нагрузки) (поток) ответа HTTP, при необходимости он сначала проверит первые несколько байтов потока, чтобы определить конкретный тип носителя (тип MIME) тела ответа (тип MIME). ). Медиа-тип тела ответа обычно можно определить по Content-Type в HTTP-заголовке, но Content-Type иногда отсутствует или неверен. В этом случае браузерОбнюхивание MIME-типадля определения типа ответа. Обнюхивание MIME-типа — непростая задача, вы можете получить его изИсходный код Chromeчтобы понять, как разные браузеры определяют, к какому типу мультимедиа принадлежит объект, на основе разных типов контента.

Заголовок ответа содержит информацию о Content-Type, а тело ответа содержит реальные данные.

Если тело ответа представляет собой HTML-файл, браузер передаст полученные данные ответа процессу визуализации для дальнейшей работы. Если полученные данные ответа представляют собой zip-файл или файл другого типа, данные ответа будут переданы диспетчеру загрузки для обработки.

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

Сетевой поток также выполняет некоторую работу с контентом, прежде чем передать его процессу рендеринга.SafeBrowsingОсмотр. Если запрошенное доменное имя или содержимое ответа соответствует известному вирусному сайту, веб-поток покажет пользователю страницу с предупреждением. В дополнение к этому сетевой поток также будет выполнятьCORB(Cross Origin Read Blocking) проверяет, чтобы конфиденциальные межсайтовые данные не отправлялись в процесс рендеринга.

Шаг 4: Найдите процесс визуализации

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

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

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

Шаг 5: Отправить (зафиксировать) навигацию

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

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

Процесс браузера инициирует запрос на рендеринг страницы в процесс рендеринга через IPC.

Дополнительный шаг: начальная загрузка завершена

Когда отправка навигации завершена, процесс рендеринга начинает загрузку ресурсов и рендеринг страницы. Я расскажу об особенностях процесса рендеринга страниц рендеринга в следующей статье. Как только процесс рендеринга «завершен», он уведомляет процесс браузера через IPC (обратите внимание, что это происходит для всех кадров на странице).onloadсобытия были инициированы и соответствующий обработчик был выполнен), то поток пользовательского интерфейса остановит вращающийся круг на панели навигации.

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

Процесс рендеринга сообщает процессу браузера через IPC, что страница была загружена.

Перейти на разные сайты

Описан один из простейших сценариев навигации! Но что произойдет, если пользователь в это время введет другой URL-адрес на панели навигации? Если это так, процесс браузера повторит предыдущие шаги, чтобы завершить навигацию по новому сайту. Однако, прежде чем процесс браузера выполнит эти действия, он должен позволить текущей странице рендеринга выполнить некоторую завершающую работу, в частности спросить, нужно ли обрабатывать текущий процесс рендеринга.beforeunloadмероприятие.

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

Уведомление:Не просто добавить на страницуbeforeunloadПрослушиватель событий, определяемая вами функция прослушивателя будет выполняться при повторной навигации по странице, поэтому это увеличит задержку повторной навигации. Функция прослушивания событий beforeunload может быть добавлена ​​только тогда, когда это абсолютно необходимо, например, когда пользователь вводит данные на странице, а данные исчезают при исчезновении страницы.

Процесс браузера сообщает процессу рендеринга через IPC, что он собирается покинуть текущую страницу и перейти на новую страницу.

Что делать, если повторная навигация инициирована внутри страницы? Например, пользователь щелкает ссылку на странице или клиентский код JavaScript выполняет что-то вродеwindow.location = "newsite.com"код. В этом случае процесс рендеринга сначала проверит, зарегистрирован ли онbeforeunloadФункция прослушивателя событий, если она есть, выполняется, и то, что происходит после выполнения, ничем не отличается от предыдущего, разница лишь в том, что запрос навигации на этот раз инициируется процессом рендеринга в процесс браузера.

Если вы повторно перейдете на другой сайт, будет запущен другой процесс рендеринга, чтобы завершить повторную навигацию, и текущий процесс рендеринга продолжит выполнение некоторой завершающей работы на текущей странице, напримерunloadВыполняется функция прослушивателя событий.Overview of page lifecycle statesВ этой статье будут представлены все состояния жизненного цикла страницы,the Page Lifecycle APIНаучит вас, как отслеживать изменения состояния страницы на странице.

Процесс браузера приказывает новому средству визуализации отобразить новую страницу, а текущему средству визуализации сделать последние штрихи.

Сценарий сервисного работника

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

Здесь важно отметить, что сервис-воркер на самом деле представляет собой просто код JavaScript, работающий внутри процесса рендеринга. Итак, вопрос в том, когда начинается навигация, как процесс браузера определяет, есть ли на сайте соответствующий сервис-воркер, и запускает процесс рендеринга для его выполнения?

На самом деле при регистрации сервис-воркера будет записан его объем (scope) (можно пройти ст.The Service Worker LifecycleУзнайте больше об областях сервис-воркеров). Когда начинается навигация, сетевой поток будет искать соответствующий сервис-воркер в области действия зарегистрированного сервис-воркера в соответствии с запрошенным доменным именем. Если есть сервис-воркер, который нажимает на URL-адрес, поток пользовательского интерфейса запускает процесс рендеринга, чтобы сервис-воркер выполнил свой код. Сервисные работники могут использовать ранее кэшированные данные или делать новые сетевые запросы.

Сетевой поток будет искать соответствующий сервис-воркер после получения задачи навигации.

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

Предварительная загрузка навигации - Предварительная загрузка навигации

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

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

Что происходит внутри процесса рендеринга

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

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

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

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

Основная задача процесса рендеринга — преобразовать HTML, CSS и JavaScript в веб-контент, с которым мы можем взаимодействовать..

Процесс рендеринга включает в себя: основной поток (main thread), несколько рабочих потоков (worker threads), поток компоновщика (compositor thread) и растровый поток (raster thread)

Разобрать

Создайте DOM

Как упоминалось выше, процесс рендеринга получит сообщение от процесса браузера для отправки навигации (commit navigation) в конце навигации, после чего процесс рендеринга начнет получать данные HTML, а основной поток также начнет синтаксический анализ полученные текстовые данные (текстовая строка) и преобразовать их в DOM (Document Object Mмодель) объект

Объект DOM — это не только внутреннее представление браузера текущей страницы, но также структура данных и API для веб-разработчиков для взаимодействия с веб-страницами через JavaScript..

Как разбирать HTML-документы в объекты DOM находится встандарт HTMLопределено в. Но в вашей карьере веб-разработчика вы, вероятно, никогда не сталкивались с ситуацией, когда браузер допустил ошибку при синтаксическом анализе HTML.Это связано с тем, что браузеры очень устойчивы к ошибкам HTML.. Например: если в абзаце отсутствует закрывающий тег p (

), страница все равно будет считаться действительным HTML; Привет! Я Chrome! (закрывающий тег b пишется перед закрывающим тегом i), несмотря на синтаксическую ошибку, браузер обработает его как Привет! Я Chrome !. Если вы хотите узнать, как браузеры обрабатывают эти ошибки, вы можете обратиться к спецификации HTML.An introduction to error handling and strange cases in the parserсодержание.

загрузка подресурсов

В дополнение к файлам HTML веб-сайты обычно используют некоторые дополнительные ресурсы, такие как изображения, стили CSS и сценарии JavaScript. Эти файлы извлекаются из кеша или из сети. Основной поток будет инициировать сетевые запросы один за другим в том порядке, в котором он сталкивается с каждым ресурсом при построении дерева DOM, но для повышения эффективности браузер одновременно запускает программу «сканер предварительной загрузки». Если в документе HTML есть такие теги, как или , сканер предварительной загрузки найдет соответствующие ресурсы, которые необходимо получить, в токене, сгенерированном парсером HTML, и сообщит браузеру обработать ресурсы, которые необходимо получить. нить.

Основной поток анализирует содержимое HTML и строит дерево DOM.

JavaScript блокирует синтаксический анализ HTML

Когда синтаксический анализатор HTML встречает тег script, он прекращает синтаксический анализ HTML-документа и обращается к коду JavaScript для загрузки, анализа и выполнения. почему ты хочешь сделать это? Поскольку JavaScript внутри тега script может использовать что-то вродеdocument.write()Такой код меняет форму потока документов, тем самым коренным образом меняя структуру всего дерева DOM (в спецификации HTMLобзор раздела модели синтаксического анализаЕсть хорошие схемы). По этой причине синтаксический анализатор HTML должен дождаться завершения выполнения JavaScript, прежде чем продолжить синтаксический анализ потока HTML-документа. Если вам интересно, что происходит с выполнением JavaScipt, у команды V8 есть много информации по этой теме.обсуждение и блог.

Дайте браузеру подсказку, как загрузить ресурс

Есть много способов, которыми веб-разработчики могут указать браузеру, как более изящно загружать ресурсы, необходимые веб-странице. Если ваш JavaScript не использует такие вещи, какdocument.write()способ изменить содержимое потока документов, вы можете добавить тег скриптаasyncилиdeferсвойство, чтобы скрипт JavaScript загружался асинхронно. Конечно, если это может удовлетворить ваши потребности, вы также можете использоватьJavaScript Module. в то же время<link rel="preload">Предварительную загрузку ресурса можно использовать, чтобы сообщить браузеру, что ресурс обязательно будет использоваться в текущей навигации и что вы хотите загрузить ресурс как можно скорее. Для получения дополнительной связанной информации вы можете прочитатьResource Prioritization - Getting the Browser to Help YouЭта статья.

Расчет стиля - Расчет стиля

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

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

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

Макет - Макет

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

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

Показатель веб-страницы также одинаково, только знание потока документов веб-сайта, а стиль каждого узла гораздо менее чем достаточно, чтобы сделать содержимое страницы, но также необходимо рассчитать каждый узел через макет.геометрическая информация(геометрия). Конкретный процесс макета выглядит следующим образом: основной поток будет проходить только что созданное дерево DOM и вычислять дерево макета в соответствии со стилем расчета узла DOM. Каждый узел в дереве компоновки имеет определенную информацию о своих координатах x, y и размерах ограничивающей рамки на странице. Дерево компоновки похоже на построенное ранее дерево DOM, за исключением того, что это дерево содержит информацию только о видимых узлах. Например, если узел установлен наdisplay:none, этот узел невидим и не будет отображаться в дереве компоновки (visibility:hiddenУзел появится над деревом компоновки, можете подумать почему). Аналогично, если узел псевдоэлемента (псевдокласса) имеет что-то вродеp::before{content:"Hi!"}Такой контент появится на макете, а не в дереве DOM.

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

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

Браузеры должны учитывать, должны ли абзацы переноситься

Если учитывать CSS, то будет сложнее, потому что CSS очень мощная штука, он может заставить элементы плавать (подплывать) к определенной стороне страницы, также он может блокировать переполнение (overflow) элементов на странице, а также может изменить содержание страницы, направление написания, так что просто подумайте об этом, и вы поймете, что процесс верстки — очень трудная и сложная задача. Для браузера Chrome у нас есть целая команда инженеров, ответственных за процесс верстки. Если вы хотите точно знать, что они делают, они находятся вBlinkOn ConferenceСоответствующее обсуждение выше было записано, вы можете посмотреть его, если у вас есть время.

живопись - Краска

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

Мужчина стоит перед холстом с кистью и думает, нарисовать ли сначала круг или квадрат.

Например, если некоторые элементы на странице установленыz-indexсвойства, порядок отрисовки элементов будет влиять на правильность страницы.

Неправильно просто рисовать элементы страницы в порядке верстки HTML, потому что не учитывается z-индекс элемента

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

Основной поток проходит по дереву компоновки для создания записей чертежей.

высокая стоимостьконвейер рендеринга(Конвейер рендеринга) обновление

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

DOM+Style, верстка и дерево рисования

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

Обновление конвейера не поспевает за обновлением экрана, а анимация немного застревает.

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

Некоторые кадры анимации заблокированы JavaScript

В этом случае JavaScript вы можете выполнить операцию, чтобы разделить на более мелкие части, а затем черезrequestAnimationFrameЭтот API выполняет их каждый кадр анимации. Для получения дополнительной информации об этом см.Optimize JavaScript Execution. Конечно, вы также можете поместить код JavaScript вWebWorkersчтобы они не блокировали основной поток.

Запустите небольшой фрагмент кода JavaScript на кадре анимации.

синтез

Как нарисовать страницу?

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

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

Самый простой процесс растеризации

что такое синтез

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

ты можешь пройтиLayers panelПосмотрите, как ваш веб-сайт разделен на разные слои браузером в DevTools.

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

наслоение страницы

Чтобы определить, какие элементы нужно разместить на каком слое, основной поток должен пройти по дереву рендеринга, чтобы создать дерево слоев (эта часть работы в DevTools называется «Обновить дерево слоев»). Если части страницы должны быть размещены на отдельном слое (скользящее меню), но это не так, вы можете сделать это с помощьюwill-changeСвойство CSS, чтобы сообщить браузеру о том, что нужно наслаивать его.

Основной поток проходит по дереву компоновки, чтобы сгенерировать иерархическое дерево.

Вы можете захотеть сделать все элементы на странице одним слоем, однако, когда на странице больше определенного количества слоев, операция компоновки слоев выполняется медленнее, чем растеризация небольшой части страницы в каждом кадре, поэтому это очень важно. для измерения производительности рендеринга вашего приложения. Для получения дополнительной информации об этом вы можете обратиться к статьеStick to Compositor-Only Properties and Manage Layer Count.

Растеризация и компоновка страниц вне основного потока

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

Растровый поток создает растровое изображение тайлов и отправляет его на графический процессор.

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

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

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

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

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

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

вход в поток композитинга

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

Входные события с точки зрения браузера

Когда вы слышите «события ввода», вы, вероятно, думаете только о том, как пользователь печатает в текстовом поле или щелкает страницу, но с точки зрения браузера ввод на самом деле означает что-то из любых жестов, сделанных пользователем. Итак, пользователь滚动页面,触碰屏幕так же как移动鼠标Такие операции можно рассматривать как входные события от пользователя.

Процесс браузера первым получает это событие, когда пользователь выполняет какой-либо жест, например касание экрана. Однако процесс браузера может знать только, где происходят жесты пользователя, но не как с ними бороться, потому что за процесс рендеринга страницы отвечает содержимое вкладки (вкладки). Таким образом, процесс браузера будетtouchstart) и координаты (координаты), отправленные в процесс рендеринга. Чтобы правильно обработать это событие, процесс рендеринга найдет целевой объект события (цель) и запустит функцию слушателя, привязанную к событию (слушатель).

События кликов перенаправляются из процесса браузера в процесс рендерера.

Поток композиции получает входное событие

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

Понимание областей с небыстрой прокруткой - область с небыстрой прокруткой

Поскольку сценарий JavaScript страницы запускается в основном потоке (main thread), при составлении страницы поток композиции пометит те области страницы, где зарегистрированы прослушиватели событий, как «области с небыстрой прокруткой» (Non- быстрая прокручиваемая область). Зная эту информацию, когда пользовательское событие происходит в этих областях, поток композиции отправляет входное событие в основной поток для обработки. Если событие ввода не происходит в области с небыстрой прокруткой, поток композитинга не требует участия основного потока для составления нового кадра.

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

Будьте осторожны при написании прослушивателей событий

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

document.body.addEventListener('touchstart', event => {
  if (event.target === area) {
    event.preventDefault()
  }
})

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

Схематическая диаграмма обработки событий страницы, когда вся страница представляет собой область небыстрой прокрутки

Чтобы предотвратить это, вы можете передать прослушиватель событийpassive:trueопции. Этот параметр сообщает браузеру, что вы по-прежнему хотите прослушивать события в основном потоке, но поток компоновки также может продолжать компоновку новых кадров.

document.body.addEventListener('touchstart', event => {
    if (event.target === area) {
        event.preventDefault()
    }
 }, {passive: true});

Найдите цель события

Когда поток композиции отправляет входное событие в основной поток, первое, что делает основной поток, — это находит цель события с помощью теста попадания. Конкретный процесс проверки попадания заключается в просмотре записей рисования, сгенерированных в конвейере рендеринга, чтобы выяснить, какой объект изображен в координатах x и y входного события.

Основной поток определяет, какой объект находится в координатах x, y, просматривая запись чертежа.

Минимизируйте количество событий, отправляемых в основной поток

В приведенной выше статье мы сказали, что частота обновления дисплея обычно составляет 60 раз в секунду и что мы можем добиться плавной анимации страницы, поддерживая частоту выполнения кода JavaScript в соответствии с частотой обновления экрана. Для пользовательского ввода сенсорный экран обычно запускает от 60 до 120 событий щелчка в секунду, в то время как мышь обычно запускает 100 событий в секунду, поэтому частота запуска событий ввода на самом деле намного выше, чем частота обновления нашего экрана.

Если каждая секунда будет похожа наtouchmoveЭто постоянно запускаемое событие отправляется в основной поток 120 раз, поскольку частота обновления экрана относительно низкая, оно может вызвать избыточные тесты кликов и выполнение кода JavaScript.

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

Чтобы свести к минимуму избыточные вызовы основного потока, Chrome объединяет последовательные события (например,wheel,mousewheel,mousemove,pointermove,touchmove) и отложить планирование до следующегоrequestAnimationFrameДо.

keydownkeyupmouseupmousedowntouchstarttouchend

touchmovegetCoalescedEvents

window.addEventListener('pointermove', event => {
    const events = event.getCoalescedEvents();
    for (let event of events) {
        const x = event.pageX;
        const y = event.pageY;
        // draw a line using x and y coordinates.
    }
});

passive:trueasync

Feature Policysync-script