предисловие
Во время нашего интервью интервьюер часто задавал такой вопрос, от ввода URL-адреса в адресной строке браузера до отображения страницы, что случилось с браузером? Этот вопрос кажется банальным, но ответ на этот вопрос хороший или плохой, он действительно может отражать широту и глубину знаний интервьюируемого.
В этой статье рассказывается с точки зрения браузера, после ввода URL-адреса и нажатия Enter, что происходит внутри браузера, после прочтения этой статьи вы узнаете:
- Каковы процессы в браузере, какую роль там?
- Что делают внутренние процессы и потоки после того, как адрес браузера вводит URL-адрес?
- Когда мы взаимодействуем с браузером, как внутренний процесс обрабатывает эти события взаимодействия
исходный адресДобро пожаловать в СТАР
архитектура браузера
Прежде чем говорить об архитектуре браузера, сначала поймите две концепции:进程
а также线程
.
Процесс - это процесс выполнения программы. Это динамическое понятие. Это основная единица для распределения ресурсов и управления ими во время выполнения программы. Поток - это основная единица для планирования и распределения ЦП. Другие потоки совместно используют все ресурсы. ресурсы, принадлежащие процессу.
Проще говоря, процесс можно понимать как исполняемое приложение, а поток можно понимать как исполнителя кода в нашем приложении. И их отношения можно представить,Потоки выполняются внутри процессов, процесс может иметь один или несколько потоков, а поток может принадлежать только одному процессу.
Как мы все знаем, браузер принадлежит приложению, и одно выполнение приложения можно понимать как запуск компьютером进程
, после запуска процесса ЦП выделит процессу соответствующее пространство памяти.Когда наш процесс получит память, ее можно будет использовать线程
Выполните планирование ресурсов, чтобы завершить функции нашего приложения.
В прикладной программе для удовлетворения функциональных потребностей запущенный процесс создаст еще один новый процесс для выполнения других задач.Если между этими процессами требуется связь, это можно сделать через механизм IPC (Inter Process Communication).
Многие приложения будут использовать этот многопроцессный подход к работе, потому что процессы и процессы независимы друг от друга.互不影响
, то есть когда один из процессов зависает, это не повлияет на выполнение других процессов, и для возобновления работы достаточно перезапустить зависший процесс.
Многопроцессорная архитектура браузера
Если мы разрабатываем браузер, его архитектура может быть многопоточным приложением с одним процессом или приложением с несколькими процессами, использующим связь IPC.
Различные браузеры используют разные архитектуры. Следующее в основном принимает Chrome в качестве примера для введения многопроцессной архитектуры браузера.
В Chrome есть 4 основных процесса:
- Процесс браузера: отвечает за TAB браузера вперед, назад, адресную строку, панель закладок и обрабатывает некоторые невидимые базовые операции браузера, такие как сетевые запросы и доступ к файлам.
- Процесс рендеринга: отвечает за работу, связанную с отображением на вкладке, также известную как механизм рендеринга.
- Процесс плагина (Plugin Process): отвечает за управление плагинами, используемыми веб-страницами.
- Процесс графического процессора: задача графического процессора, отвечающая за обработку всего приложения.
Какова связь между этими четырьмя процессами?
Прежде всего, когда мы хотим просмотреть веб-страницу, мы вводим URL-адрес в адресную строку браузера, на этот разBrowser Process
Отправит запрос на этот URL-адрес, получит HTML-содержимое этого URL-адреса, а затем передаст HTML-кодRenderer Process
,Renderer Process
Разобрать содержимое HTML, разобрать ресурсы, которые необходимо запросить в сети, и вернуть их вBrowser Process
загружать и уведомлять одновременноBrowser Process
,нужноPlugin Process
Загрузите ресурсы плагина и выполните код плагина. После завершения разбораRenderer Process
Вычислите кадры изображения и передайте эти кадры изображенияGPU Process
,GPU Process
Преобразуйте его в экран отображения изображения.
Преимущества многопроцессорной архитектуры
Почему Chrome использует многопроцессорную архитектуру?
Во-первых, более высокая отказоустойчивость. В современных веб-приложениях HTML, JavaScript и CSS становятся все более и более сложными. Эти коды, работающие в механизме рендеринга, часто вызывают ошибки, а некоторые ошибки напрямую приводят к сбою механизма рендеринга. Архитектура с несколькими процессами заставляет работать каждый механизм рендеринга. в своем собственном процессе. , которые не зависят друг от друга, то есть, когда одна из страниц дает сбой и зависает, другие страницы могут нормально работать, не подвергаясь влиянию.
Во-вторых, более высокая безопасность и санбоксинг. Механизм рендеринга часто сталкивается с ненадежным или даже вредоносным кодом в сети и использует эти уязвимости для установки вредоносного программного обеспечения на ваш компьютер.В ответ на эту проблему браузеры ограничивают разные разрешения для разных процессов и предоставляют ему запущенную песочницу. среду, делая ее более безопасной и надежной
Третий, более высокая скорость отклика. В архитектуре однопроцесс различные задачи соревнуются друг с другом для ресурсов ЦП, что делает ответ браузера медленнее, а многопроцессная архитектура просто позволяет избежать этого недостатка.
Оптимизация многопроцессной архитектуры
Раньше мы говорили,Renderer Process
Его роль заключается в том, чтобы отвечать за работу, связанную с отображением на вкладке, что означает, что вкладка будет иметь процесс визуализации, память между этими процессами не может быть разделена, а память разных процессов часто должна содержать одно и то же содержимое.
режим процесса браузера
В целях экономии памяти Chrome предоставляет четыре режима процесса (модели процесса), и разные режимы процесса по-разному обрабатывают процесс вкладок.
- Process-per-site-instance(по умолчанию) - то же самоеsite-instanceиспользовать процесс
- Process-per-site -тот самыйsiteиспользовать процесс
- Process-per-tab -Используйте один процесс на вкладку
- Single process -Все вкладки разделяют один процесс
Здесь нужно дать определение сайта и сайта-экземпляра
- siteОтносится к тому же зарегистрированному доменному имени (например, google.com, bbc.co.uk) и схеме (например, https://). Например, a.baidu.com и b.baidu.com можно понимать как один и тот же сайт (обратите внимание, чтоSame-origin policyЧтобы различать, политика одного и того же происхождения также включает поддомены и порты).
-
site-instanceозначает группуconnected pages from the same site,здесьconnectedопределяется какcan obtain references to each other in script codeКак понять это предложение. Если выполняются следующие два условия и открытая новая страница и старая страница принадлежат одному и тому же сайту, определенному выше, они принадлежат одному и тому же сайту.site-instance
- пользователь через
<a target="_blank">
Нажмите здесь, чтобы открыть новую страницу - Новая страница, открытая кодом JS (например,
window.open
)
- пользователь через
После понимания концепции четыре режима процесса объясняются ниже.
прежде всегоSingle process
, как следует из названия, режим одного процесса, все вкладки будут использовать один и тот же процесс. ДалееProcess-per-tab
, как следует из названия, при каждом открытии вкладки будет создаваться новый процесс. И дляProcess-per-site
, когда вы открываете страницу a.baidu.com, когда вы открываете страницу b.baidu.com, вкладки этих двух страниц используют один и тот же процесс, потому что сайты этих двух страниц одинаковы, и в результате если на одном из них крашится одна вкладка, крашится и другая вкладка.
Process-per-site-instance
Это самое главное, потому что это модель Chrome по умолчанию, то есть почти все пользователи используют этот режим. Когда вы открываете Tab Access A.Baidu.com, а затем открываете Tab Access B.Baidu.com, эти две TAB будут использоватьдва процесса. И если вы откроете страницу b.baidu.com через JS-код в a.baidu.com, эти две вкладки будут использоватьтот же процесс.
Выбор режима по умолчанию
Итак, почему браузеры используютProcess-per-site-instance
Как режим процесса по умолчанию?
Process-per-site-instance
Совместимый с производительностью и простотой использования, это более умеренный и общий режим.
- По сравнению с Process-per-tab, возможность открывать множество процессов означает меньшее использование памяти.
- По сравнению с Process-per-site, он может лучше изолировать несвязанные вкладки под одним и тем же доменным именем и является более безопасным.
что случилось с навигацией
Ранее мы говорили о многопроцессорной архитектуре браузера, различных преимуществах многопроцессорной архитектуры и о том, как Chrome оптимизирует многопроцессорную архитектуру. понимание того, как работают процессы и потоки Рендеринг страниц нашего сайта.
процесс загрузки веб-страницы
Прежде чем мы упомянули, что большая часть работы, кроме TAB, выполняется в процессе браузера.Browser Process
Ответственный за разные задания Browser Process делит разные рабочие потоки:
- Поток пользовательского интерфейса: кнопки управления и поля ввода в браузере;
- сетевой поток: обработка сетевых запросов и получение данных из Интернета;
- поток хранения: контроль доступа к файлам и т.д.;
Шаг 1. Обработайте ввод
Когда мы вводим контент в адресной строке браузера и нажмите Enter,UI thread
Он определит, является ли входное содержимое ключевым словом для поиска (поисковым запросом) или URL-адресом. Если это ключевое слово для поиска, оно перейдет к поисковой системе по умолчанию для поиска соответствующего URL-адреса. Если входное содержимое является URL-адресом, оно начнет запрашивать URL.
Шаг 2: Запустите навигацию
После нажатия Enter,UI thread
Отправьте URL-адрес, соответствующий поиску по ключевому слову, или входной URL-адрес в сетевой потокNetwork thread
В это время значок, чтобы показать ниту пользовательского интерфейса до накладки загружен в состояние, а затем серию сетевых процессов, таких как DNS-адресация, а также другие операции, для установления запроса ресурса подключения TLS, если вы получаете ответ на перенаправление 301 Сервер, он будет информировать потоку пользовательского интерфейса, а затем перенаправить его снова запустит новый запрос сети.
Третий шаг: прочитайте ответ
network thread
Получив ответ от сервера, начните разбор сообщения HTTP-ответа, затем заголовок ответаContent-Type
поле для определения типа мультимедиа (тип MIME) тела ответа. Если тип мультимедиа — файл HTML, данные ответа будут переданы в процесс визуализации для следующего шага. Если это ZIP-файл или другой файл, он будет отправлен в процесс рендерера, а соответствующие данные будут переданы в менеджер загрузок.
При этом браузер будетSafe BrowsingПроверка безопасности. Если доменное имя или содержимое запроса соответствуют известному вредоносному сайту, Network Thread покажет страницу с предупреждением. Кроме того, сетевой поток также будет выполнятьCORB(Блокировка чтения между источниками) Установите этот флажок, чтобы определить, что конфиденциальные межсайтовые данные не будут отправляться в процесс рендеринга.
Шаг 4: Найдите процесс рендеринга
После завершения различной проверки сетевая резьба уверена, что браузер может перейти к запросу веб-страницы, сетевой поток уведомляет, что данные потока пользовательского интерфейса будут готовы, поток UI найдет процесс рендеринга для рендеринга веб-страниц.
Чтобы браузер оптимизировал шаг поиска процесса рендеринга, учитывая, что для получения ответа на сетевой запрос требуется время, браузер уже заранее нашел и запустил процесс рендеринга в начале второго шага. промежуточные шаги проходят успешно, когда сетевой поток. Когда данные получены, процесс рендеринга готов, но если встречается перенаправление, подготовленный процесс рендеринга может быть недоступен, и в это время процесс рендеринга будет перезапущен.
Шаг 5: Отправить навигацию
На данный момент процессы данных и рендеринга готовы,Browser Process
будуRenderer Process
Отправьте сообщение IPC, чтобы подтвердить навигацию. В это время процесс браузера отправляет подготовленные данные в процесс рендеринга. После того, как процесс рендеринга получит данные, он отправляет сообщение IPC процессу браузера, чтобы сообщить процессу браузера, что навигация отправлено, и страница начинается load.
В это время навигационная панель будет обновляться, индикатор безопасности будет обновлен (небольшой замок перед адресом), а вкладки истории доступа будет обновляться, то есть вы можете переключить страницу, идущая вперед или назад Отказ
Шаг шесть: нагружена инициализация
Когда отправка навигации завершена, начинается процесс рендеринга для загрузки ресурсов и рендеринга страницы (подробности описаны ниже). будет отправлен в процесс браузера, чтобы сообщить браузеру.Процесс сервера, в это время поток пользовательского интерфейса перестанет отображать значок загрузки на вкладке.
Принцип рендеринга веб-страницы
После завершения процесса навигации процесс браузера передает данные процессу рендеринга. Процесс рендеринга отвечает за все на вкладке. Основная цель — преобразовать код HTML/CSS/JS в веб-страницы, с которыми пользователи могут взаимодействовать . Так как же работает процесс рендеринга?
В процессе рендеринга включаются следующие потоки:
- основной поток
- Несколько рабочих потоков
- Синтез потока (резьба композиторов)
- Несколько растровых потоков
Различные потоки имеют разные рабочие обязанности.
Создайте DOM
Когда процесс рендеринга получает информацию о подтверждении навигации, он начинает принимать данные от процесса браузера.В это время основной поток будет анализировать данные и преобразовывать их в объект DOM (объектная модель документа).
DOM — это структура данных и API для веб-разработчиков для взаимодействия с веб-страницами через JavaScript.
подзагрузка ресурсов
В процессе построения DOM ресурсов, таких как изображения, CSS и JavaScript, будут проанализированы. Эти ресурсы должны быть получены из сети или кеша. Если основной поток сталкивается с этими ресурсами в процессе построения дома, это Инициируют запросы, чтобы получить их один за другим. Чтобы повысить эффективность, браузер также будет запустить программу сканера PRELOAD (сканер PRELOAD), если HTML существуетimg
,link
и другие теги, сканер предварительной загрузки будет передавать эти запросы вBrowser Process
Сетевой поток для загрузки ресурсов.
Загрузка и выполнение JavaScript
Процесс здания DOM, если вы столкнулись<script>
Метка, механизм рендеринга прекратит синтаксический анализ HTML, попытается выполнить загруженный код JS, поскольку код JS может изменить структуру DOM (например, выполнениеdocument.write()
Подождите API)
Однако на самом деле у разработчиков есть много способов сообщить браузеру, как реагировать на ресурс, например, если<script>
Добавить ярлыкasync
илиdefer
и другие свойства, браузер будет асинхронно загружать и выполнять код JS, не блокируя рендеринг.
Расчет стиля - Расчет стиля
Дерево DOM — это всего лишь структура нашей страницы.Нам нужно знать, как выглядит страница, а также нужно знать стиль каждого узла DOM. Когда основной поток анализирует страницу, он встречает<style>
этикетка или<link>
Ресурс label CSS загрузит код CSS, определит стиль вычисления каждого узла DOM в соответствии с кодом CSS.
Вычисляемые стили — это определенные стили, которые каждый элемент DOM должен вычислить в основном потоке на основе селекторов CSS.Даже если на вашей странице не установлены пользовательские стили, браузер предоставит стили по умолчанию.
Макет - Макет
После того, как DOM-дерево и стиль расчета завершены, нам также необходимо знать положение каждого узла на странице Макет — это фактически процесс нахождения геометрического соотношения всех элементов.
Основной поток будет проходить стили расчета DOM и связанных элементов и строить дерево компоновки (Дерево рендеринга), содержащее информацию о координатах страницы каждого элемента и размер блочной модели.В процессе обхода скрытые элементы (отображение: none) будут пропущены.Кроме того, псевдоэлементы, хотя и невидимы в DOM, видны в дереве компоновки.
рисовать - раскрашивать
После верстки макета мы знаем структуру, стиль и геометрическое соотношение различных элементов.Мы хотим нарисовать страницу.Нам нужно знать последовательность рисования каждого элемента.На этапе рисования основной поток будет проходить по макету tree (дерево макета) , которое генерирует серию записей рисования. Запись чертежа можно рассматривать как примечание, в котором записана последовательность рисования каждого элемента.
Композитинг - Композитинг
У нас есть структура документа, стиль элемента, геометрическое соотношение элементов и порядок отрисовки. У нас есть вся эта информация. Если мы хотим отрисовать страницу в это время, нам нужно преобразовать эту информацию в пиксели на дисплее. , Этот процесс преобразования, называемый光栅化
(растрирование).
Затем мы хотим нарисовать страницу, самый простой способ — растрировать только содержимое страницы в области просмотра, если пользователь прокручивает страницу, переместить растровый фрейм (растровый фрейм) и растрировать больше контента, чтобы составить страницу. части следующие:
В первой версии Chrome использовался этот простой метод рисования. Единственный недостаток этого метода заключается в том, что всякий раз, когда страница прокручивается, растровый поток должен растрировать содержимое, только что перемещенное в представление, что приводит к определенной потере производительности. В этом случае Chrome использует более сложный подход, называемый композитингом.
Итак, что такое синтез? синтез представляет собойСтраницы разделены на слои, затем растеризуйте их по отдельности и, наконец, объедините их в одну страницу в одном потоке — потоке компоновщика. Когда пользователь прокручивает страницу, поскольку все слои страницы были растеризованы, все, что нужно сделать браузеру, — это синтезировать новый кадр для отображения эффекта прокрутки. Эффект анимации страницы также аналогичен, просто переместите слой на странице и создайте новый кадр.
Чтобы реализовать технологию композиции, нам нужно распределить элементы по слоям, чтобы определить, какие элементы нужно поместить в какой слой, а основной поток должен пройти по дереву рендеринга, чтобы создать дерево слоев.will-change
Элементы со свойствами CSS рассматриваются как отдельный слой, безwill-change
Элементы со свойствами CSS, браузер решит, следует ли поместить элемент в отдельный слой в зависимости от ситуации.
Вы можете захотеть сделать все элементы на странице одним слоем, однако, когда на странице больше определенного количества слоев, операция компоновки слоев выполняется медленнее, чем растеризация небольшой части страницы в каждом кадре, поэтому это очень важно. для измерения производительности рендеринга вашего приложения.
После создания Layer Tress определяется порядок рендеринга, основной поток передает информацию в синтезатор, количество потоков синтезатора, запускаемых на уровне каждого слоя, растрируется. Некоторые слои могут достигать размера всей страницы, поэтому их необходимо нарезать синтетической нитью на небольшой фрагмент тайла (Tiles), после чего мелкие тайлы передаются в серию растровых потоков (raster threads), производилась растеризация, решетка результаты после окончания каждого тайла будут существовать растровые потокиGPU Process
в памяти.
Чтобы оптимизировать отображение, синтетическому потоку можно присвоить разные приоритеты для разных потоков решетки, слоя рядом с теми, что находятся в окне просмотра, или в окне просмотра, которое нужно растрировать.
Когда плитка над слоем представляет собой сетку, синтетическая нить собирает таблетку на столе.рисование четырехугольника(нарисовать квадроциклы) информация для построениясоставная рама(кадр композитора).
- рисовать квадраты: включить плитки вячейка памятиИ такая информация, как положение плитки на странице после компоновки слоя.
- Составной фрейм: четырехугольник для рисования, представляющий содержимое одного фрейма страницы.собирать.
После того, как все вышеперечисленные шаги выполнены, поток компоновки передает визуализированный кадр в процесс браузера через IPC. В это время другой составной кадр может быть отправлен потоком пользовательского интерфейса процесса браузера для изменения пользовательского интерфейса браузера. Эти составные кадры отправляются на графический процессор для отображения на экране. Если поток композитинга получает событие прокрутки страницы, поток композитинга создает еще один кадр композитинга и отправляет его в графический процессор для обновления страницы.
Преимущество компоновки в том, что в этом процессе не участвует основной поток, поэтому потоку компоновки не нужно ждать, пока будут вычислены стили и завершится выполнение JavaScript. поэтомуСинтезатор, связанная с анимациейСамый плавный, если анимация предполагает корректировку макета или отрисовки, то она будет включать в себя пересчет основного потока, который, естественно, будет намного медленнее.
Браузерная обработка событий
После рендеринга страницы интерактивная WEB-страница отобразилась в TAB, и пользователь может перемещать мышь, щелкать по странице и т. д., и когда происходят эти события, как браузер обрабатывает эти события?
Возьмем в качестве примера событие щелчка. Когда мышь щелкает страницу, первым, что получает информацию о событии, являетсяBrowser Process
, но процесс браузера знает только тип и местоположение события.Как обрабатывать событие клика по-прежнему определяется вкладкой во вкладке.Renderer Process
непрерывный. После того, как процесс браузера получает событие, он передает информацию о событии в процесс рендеринга.Процесс рендеринга найдет координаты в соответствии с событием, найдет целевой объект (цель) и запустит функцию слушателя, привязанную к событию щелчка целевой объект (слушатель).
Поток композитора получает события в процессе рендеринга
Как мы упоминали ранее, поток компоновщика может создавать составные кадры через растеризованные слои независимо от основного потока, например прокрутки страницы.Если нет событий, связанных с прокруткой страницы, поток композитора может создавать составные кадры независимо от основного потока. , если страница привязана к событию прокрутки страницы, поток компоновщика будет ждать, пока основной поток обработает событие перед созданием объединенного фрейма. Итак, как поток компоновщика определяет, нужно ли перенаправлять событие в основной поток для обработки?
Поскольку выполнение JS — это работа основного потока, при синтезе страницы поток компоновщика пометит область страницы, связанную с обработчиком события, как非快速滚动区域
(область с небыстрой прокруткой), если событие происходит в этих отмеченных областях, поток компоновщика отправит информацию о событии в основной поток и будет ждать, пока основной поток обработает событие. Если событие не происходит в этих областях, поток компоновщика будет синтезировать новые кадры напрямую, не дожидаясь ответа от основного потока.
Для тегов в областях с небыстрой прокруткой разработчикам нужно обратить внимание на привязку глобальных событий.Например, мы используем делегирование событий для передачи событий целевого элемента в тело корневого элемента для обработки.Код выглядит следующим образом:
document.body.addEventListener('touchstart', event => {
if (event.target === area) {
event.preventDefault()
}
})
С точки зрения разработчика этот кусок кода хорош, но с точки зрения браузера этот кусок кода привязывает прослушиватель событий к элементу body, а это означает, что вся страница редактируется в область небыстрой прокрутки. , который будет даже если некоторые области вашей страницы не привязаны к каким-либо событиям, каждый раз, когда пользователь инициирует событие, поток компоновщика должен взаимодействовать с основным потоком и ждать обратной связи, а режим плавного компоновщика обрабатывать составной кадр самостоятельно становится недействительным.
На самом деле, с этой ситуацией также легко справиться, просто передайте ее, когда событие прослушивается.passtive
Параметр правда,passtive
Это сообщит браузеру, что вы должны не только привязать событие, но и позволить потоку объединителя пропустить обработку событий основного потока и напрямую объединить для создания объединенного кадра.
document.body.addEventListener('touchstart',
event => {
if (event.target === area) {
event.preventDefault()
}
}, {passive: true});
Найдите цель события
Когда поток компоновщика получает информацию о событии и определяет, что событие не находится в области небыстрой прокрутки, поток компоновщика отправляет информацию об этом времени в основной поток.Первое, что основной поток получает информацию о событии, это передать хит test (проверка попадания). ) для поиска целевого объекта события. Конкретный процесс проверки попадания заключается в просмотре записей рисования, созданных на этапе рисования, для поиска объекта элемента, который содержит координаты события.
Браузерная оптимизация событий
Как правило, частота кадров нашего экрана составляет 60 кадров в секунду, что составляет 60 кадров в секунду, но частота срабатывания некоторых событий превышает это значение, таких как колесо, колесо мыши, движение мыши, перемещение указателя, движение касания, Эти непрерывные события обычно вызывают 60 событий в секунду. ~ 120 раз, если каждый раз, когда событие запускается, событие отправляется в основной поток для обработки, поскольку частота обновления экрана относительно низкая, поэтому основной поток будет запускать избыточные тесты попаданий и код JS, снижая производительность. ненужная потеря.
В целях оптимизации браузер объединит эти последовательные события и задержит выполнение рендеринга следующего кадра, то естьrequestAnimationFrame
До.
Для несвязанных событий, таких как KeyDown, Keyup, MouseDown, Mouseup, Touchstart, Touchend и т. д., они будут отправлены непосредственно в основной поток.
Суммировать
Многопроцессорная архитектура браузера разделяет разные процессы в соответствии с разными функциями.Различные задачи в процессе делятся на разные потоки.Когда пользователь начинает просматривать веб-страницу, процесс браузера обрабатывает ввод, начинает перемещаться по данным запроса , и запрашивает данные ответа. , найти новый процесс рендеринга, отправить навигацию, а затем процесс рендеринга анализирует HTML для построения DOM, загружает подресурсы в процессе построения, загружает и выполняет код JS, расчет стиля , макет, рисование, синтез и шаг за шагом строит интерактивный веб-сайт. После этого процесс браузера принимает информацию об интерактивном событии страницы и передает ее процессу рендеринга. Основной процесс в процессе рендеринга выполняет тестирование попадания, находит целевой элемент и выполняет связанное событие, чтобы завершить взаимодействие со страницей.
Большая часть этой статьи также является правдойinside look at modern web browserСортировка, интерпретация и перевод серии статей, процесс сортировки по-прежнему очень полезен, надеюсь, читатели только вдохновятся после прочтения этой статьи.