Русский
Русский
English
Статистика
Реклама

Перевод Устройство современного веб-браузера Chrome (часть 44)

Это последний пост из серии 4-х постов, посвященной заглядыванию внутрь Chrome, и исследующей, как он обрабатывает наш код для отображения веб-сайта. В предыдущем посте мы рассмотрели *рендер-процесс (renderer process) и узнали о *композ-потоке (compositor thread). В этом посте мы рассмотрим, как *композ-поток обеспечивает плавное взаимодействие при вводе данных пользователем.



Часть 1
Часть 2
Часть 3
Часть 4 (текущая)


Об особенностях перевода
  • в ходе перевода, я старался вычленять из статьи ПОНЯТИЯ, т.е. текстовые единицы которые несут специальный (технический) смысл. В переводе эти понятия выделены по особенному во первых понятия предваряются символом звёздочки, во-вторых в них вместо пробела используется тире. Например: *браузер-процесс, *сайто-изоляция. При переводе понятий, приоритет отдавался не красоте перевода, а желанию выделить, акцентировать, то что мы имеем дело с ПОНЯТИЕМ, а не с фигурой речи.
  • также, некоторые слова переведены неверно с точки зрения русского языка, в жаргонном стиле, например пайплайн, продакшен. У "технарей" такой перевод не вызовет затруднений, у остальных читателей прошу прощения.

События ввода из виджетов браузера


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


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


image


Рисунок 1: Событие ввода проходит через *браузер-процесс в *рендер-процесс


*Композ-поток получает события ввода


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


image
Рисунок 2: Viewport наводится на слои страницы


Понятие *нбс-региона


Поскольку выполнение JavaScript является задачей главного потока, при компоновке страницы *композ-поток отмечает область страницы, к которой прикреплены обработчики событий как "Non-Fast Scrollable Region" (*нбс-регион). Обладая этой информацией, *композ-поток может гарантировать, что входное событие будет отправлено в главный поток, если событие произойдет в этом регионе. Если входное событие приходит из-за пределов этого региона, то *композ-поток продолжает композицию нового кадра, не дожидаясь главного потока.


image


Рисунок 3: Схема описывающая ввод в *нбс-регион


= Знайте когда вы пишете обработчики событий


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


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

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


image


Рисунок 4: Схема описывающая ввод в *нбс-регион покрывающий всю страницу


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


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

Проверка является ли событие cancelable


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


Использование опции passive: true в событии курсора означает, что прокрутка страницы может быть гладкой, но вертикальная прокрутка может начаться к тому времени, когда вы хотите выполнить preventDefault для ограничения направления прокрутки. Вы можете проверить это, используя метод event.cancelable.


image
Рисунок 5: Веб-страница с частью страницы у которой скролл только горизонтальный


document.body.addEventListener('pointermove', event => {    if (event.cancelable) {        event.preventDefault(); // блокировка нативного скрола        /*        * сделать то что вам нужно        */    }}, {passive: true});

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


#area {  touch-action: pan-x;}

Поиск цели события


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


image


Рисунок 6: Главный поток ищет *записи-отрисовки запрашивая что нарисовано в точке x.y


Минимизация распространения события в главный поток


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


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


image


Рисунок 7: События забивают временнУю ленту кадров что приводит к дрожанию страницы


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


image


Рисунок 8: Та же лента но события *коалесируются и придерживаются


Любые дискретные события, такие как нажатие keydown, keyup, mouseup, mousedown, touchstart и touchchend отправляются немедленно.


Использование getCoalescedEvents для получения межкадровых событий


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


image


Рисунок 9: Плавный путь от жеста касания слева, рваный из-за *коалесирований пути справа


window.addEventListener('pointermove', event => {    const events = event.getCoalescedEvents();    for (let event of events) {        const x = event.pageX;        const y = event.pageY;        /* отрисовка линии используя координаты x и y */    }});

Следующие шаги


В этой серии постов мы рассмотрели внутреннюю работу веб-браузера. Если вы никогда не задумывались о том, почему DevTools рекомендует добавлять {passive: true} в обработчик событий или зачем писать атрибут async в теге сценария, я надеюсь, что эта серия прольёт некоторый свет на то, почему браузеру нужна эта информация для обеспечения более быстрой и плавной работы с веб.


= Использование Lighthouse


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


= Изучаем как измерять производительность


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


= Добавление Feature Policy на ваш сайт


Если вы хотите сделать дополнительный шаг, Feature Policy это новая функция веб-платформы, которая может быть ограждением для вас, когда вы строите свой проект. Включение Feature Policy гарантирует определенное поведение вашего приложения и предотвращает ошибки. Например, если вы хотите гарантировать, что ваше приложение никогда не будет блокировать парсинг, вы можете запустить ваше приложение на основе политики синхронных сценариев. При включённом sync-script: 'none', блокирование JavaScript-ом парсера будет отключено. Это не позволит ни одному вашему коду заблокировать парасер, а браузеру будет не нужно беспокоиться о том, чтобы ставить парсер на паузу.


Итог


Когда я начинала создавать сайты, меня волновало только то, как я буду писать свой код и что поможет мне быть более продуктивной. Это важно, но мы также должны думать о том, как браузер принимает код, который мы пишем. Современные браузеры вкладывали и продолжают вкладывать средства в то, чтобы предоставить пользователям более качественный веб-интерфейс. Будьте любезны с браузером, организовывая наш код, и тем самым также, улучшая свой пользовательский опыт. Надеюсь, Вы присоединитесь ко мне в стремлении быть добрее к браузерам!


image


Огромное спасибо всем, кто рецензировал ранние проекты этой серии, включая (но не ограничиваясь): Alex Russell, Paul Irish, Meggin Kearney, Eric Bidelman, Mathias Bynens, Addy Osmani, Kinuko Yasuda, Nasko Oskov, и Charlie Reis.


Вам понравилась эта серия? Если у вас есть вопросы или предложения для будущих постов, я бы хотела услышать их от вас в разделе комментариев ниже или у меня в твиттере @kosamari.


Часть 1
Часть 2
Часть 3
Часть 4 (текущая)

Источник: habr.com
К списку статей
Опубликовано: 22.11.2020 02:06:11
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Разработка веб-сайтов

Браузеры

Архитектура приложений

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru