Цикл событий, цикл событий, процесс потока. Эти концепции могут сбивать с толку студентов, которые плохо знакомы с внешним интерфейсом. А средой выполнения для запуска js-кода является не только браузер, но и node. Поэтому обработка Event Loops в разных средах становится разной, что очень легко спутать. Если у вас есть такие сомнения. Следующее даст вам ясное объяснение.
Концепция кардинга
Во-первых, давайте упростим концепцию и разберем понятия процесса, потока и цикла обработки событий. Когда концепция ясна, она найдет отклик при дальнейшем использовании.
Основные понятия процессов и потоков
Возьмите понятия из учебника:
1. Планирование: поток — это основная единица планирования и распределения, а процесс — основная единица владения ресурсами;
2. Параллелизм: не только процессы могут выполняться одновременно, но и несколько потоков одного и того же процесса могут выполняться одновременно;
3. Владение ресурсами: процесс является независимой единицей, которая владеет ресурсами.Потоки не владеют системными ресурсами, но могут получать доступ к ресурсам, принадлежащим процессу;
4. Системные накладные расходы: при создании или отзыве процесса, поскольку система должна выделять и возвращать ресурсы для него, системные накладные расходы значительно превышают накладные расходы на создание или отзыв потоков.
Отношения между процессами и потоками:
- Поток может принадлежать только одному процессу, а процесс может иметь несколько потоков, но по крайней мере один поток;
- Ресурсы выделяются процессу, и все потоки одного и того же процесса совместно используют все ресурсы процесса;
- Процессор назначается потоку, то есть поток действительно выполняется на процессоре;
- Потоки нуждаются в совместной синхронизации во время процесса выполнения. Потоки различных процессов должны быть синхронизированы посредством обмена сообщениями. Поток — это исполнительная единица внутри процесса и планируемая сущность внутри процесса.
На первый взгляд это может не понравиться. Но с самой основной идеей процесс может иметь несколько потоков, и потоки могут взаимодействовать друг с другом. Этих двух пунктов достаточно, чтобы вы поняли знание последующего цикла событий.
Процессы, потоки и циклы событий в браузере
процесс браузера
- Начиная с открытия браузера, открывая браузер, первое, что мы видим, это пользовательский интерфейс, где есть окно поиска, область отображения и избранное. Они выделяют процесс.
- Мы видим, что браузер сам будет реализовывать какое-то локальное хранилище, куки и т. д., и на эти операции также нужно выделить процесс.
Потоки ядра браузера
Затем посмотрите, какие потоки включены в движок браузера (процесс)
- Поток рендеринга пользовательского интерфейса Отвечает за рендеринг интерфейса браузера, анализ HTML, CSS, построение дерева DOM и дерева RenderObject, компоновку и рисование и т. д. Когда интерфейс нужно перекрасить (Repaint) или вызвать какую-то операцию, чтобы вызвать перекомпоновку (reflow), этот поток будет выполняться
注意
: поток рендеринга пользовательского интерфейса и поток механизма JS являются взаимоисключающими. Когда механизм JS выполняется, поток графического интерфейса пользователя будет приостановлен (эквивалентно заморозке), а обновления пользовательского интерфейса будут сохранены в очереди и выполнены сразу же после запуска механизма JS. праздный.
- js engine thread (поток синтаксического анализа JS) Также известное как ядро JS, отвечает за обработку скриптов Javascript. (например, двигатель V8) Поток движка JS отвечает за синтаксический анализ сценариев Javascript и выполнение кода. JS-движок ждал поступления задач в очередь задач, а затем обрабатывал их.На вкладке (процессе рендеринга) в любое время __только один поток JS запускает программу JS__
同样注意
: поток рендеринга пользовательского интерфейса и поток движка JS являются взаимоисключающими, поэтому, если время выполнения JS слишком велико, рендеринг страницы будет несогласованным, а рендеринг и загрузка страницы будут заблокированы.
- поток триггера события __принадлежит браузеру__, а не движку JS, который используется для управления циклом событий (понятно, что сам движок JS слишком занят, и браузеру нужно открыть другой поток, чтобы помочь) Когда движок JS выполняет блоки кода, такие как setTimeOut (также из других потоков в ядре браузера, таких как щелчки мышью, асинхронные запросы AJAX и т. д.), соответствующие задачи будут добавлены в поток событий. Когда соответствующее событие удовлетворяет условиям срабатывания и срабатывает, поток добавит событие в конец очереди ожидания и будет ждать, пока JS-движок обработает его.
注意
: из-за однопоточной связи JS события в этих ожидающих очередях должны быть поставлены в очередь для обработки механизмом JS (выполняются только тогда, когда механизм JS простаивает).
- синхронизированный триггерный поток Поток, в котором находятся легендарные setInterval и setTimeout Счетчик времени браузера не учитывается механизмом JavaScript (поскольку механизм JavaScript является однопоточным, если он находится в состоянии заблокированного потока, это повлияет на точность времени) Поэтому для определения времени и запуска времени используется отдельный поток (после того, как время завершено, оно добавляется в очередь событий и выполняется после ожидания простоя JS-движка).
注意
:W3C предусматривает в стандарте HTML, что временной интервал менее 4 мс в setTimeout должен считаться 4 мс.
- Асинхронный поток HTTP-запросов После подключения XMLHttpRequest через браузер открывается новый запрос потока. При обнаружении изменения состояния, если установлена функция обратного вызова, асинхронный поток сгенерирует событие изменения состояния и поместит обратный вызов в очередь событий. А затем выполняется движком JavaScript.
Цикл событий механизма рендеринга js
Или больше тем, каждая может придумать подробный говорит. Анализ некоторых механизмов работы Event Loop с участием движка JS. Нас можно понять как эти нити,
- Один основной процесс — это движок js, а остальные — вспомогательные потоки.
- Основной процесс имеет стек выполнения, а поток триггера события поддерживает очередь сообщений.
- Синхронные задачи выполняются в стеке выполнения, а асинхронные задачи добавляются в очередь сообщений после выполнения условий, ожидающих выполнения.
- Сначала выполните задачи в стеке.После завершения выполнения проверьте, пуста ли очередь или нет, и поместите задачи в очереди в стек выполнения для выполнения. пока стек и очередь не опустеют. Цикл событий механизма рендеринга js выглядит следующим образом.
setTimeout(function(){
console.log(0)
},500)
setTimeout(function(){
console.log(1)
},1000)
setTimeout(function(){
console.log(2)
},2000)
for(;;){
}
Приведенный выше код не используется для вывода, а бесконечный цикл синхронного кода блокирует стек выполнения. Хотя обратный вызов добавляется в очередь выполнения после отсчета времени, исключение никогда не будет выполнено.
Тема вторая:
setTimeout(function(){
console.log('setTimeout1');
Promise.resolve().then(()=>{
console.log('then1');
});
},0)
Promise.resolve().then(()=>{
console.log('then2');
Promise.resolve().then(()=>{
console.log('then3');
})
setTimeout(function(){
console.log('setTimeout2');
},0)
})
Ответ: потом 2 потом setTimeout потом 1 setTimeout 2
Во-первых, обещание es6 появилось в заголовке, и его появление внесло некоторые изменения в понятный нам цикл __event.
Зачем? Потому что в Promise есть новая концепция: микрозадача.
На данный момент JS делится на два типа задач: макрозадачи и микрозадачи, В ECMAScript микрозадачи называются заданиями, а макрозадачи могут называться задачами.
Микрозадачи и макрозадачи
В первую очередь он основан на логике выполнения под __ браузером как средой обработки __
Что такое микрозадачи и макрозадачи в среде браузера
Задача макроса: setTimeout setImmediate MessageChannel
Микрозадача: Promise.then MutationObserver
Помните две вещи:
- Выполнение микрозадач перед макрозадачами, сначала выполнить содержимое стека выполнения, а затем очистить микрозадачи после выполнения
- Каждый раз, когда извлекается задача макроса, микрозадача очищается, а затем извлекается задача макроса.
Затем в теме начинается анализ выполнения макрозадач и микрозадач.
- setTimeout1 помещается в очередь выполнения макрозадачи, микрозадача then2 помещается в очередь микрозадачи, стек пуст, сначала выполняется микрозадача, затем сначала выполняется then2.
- После выполнения then2 существует следующая микрозадача then3. Поместите then3 в очередь микрозадач.
- Следующий setTimeout2 добавляется в очередь задач макроса.
- В этот момент стек выполнения пуст, и выполняется then3.
- После выполнения всех микрозадач выполнить макрозадачу setTimeout1, выполнить найденную микрозадачу then1 и поместить ее в очередь микрозадач.
- После выполнения макрозадачи setTimeout1 очередь микрозадач снова очищается, а затем выполняется1
- После выполнения всех микрозадач выполняется макрозадача setTimeout2. Программа заканчивается.
Процессы и потоки в среде выполнения узла
Node.js — это среда выполнения JavaScript, основанная на движке Chrome V8. Его цель — проанализировать код js, чтобы он мог работать.
узел js является однопоточным
Как и в среде браузера, у него есть основной поток для анализа js и другие потоки в качестве вспомогательных, но поскольку он не требует работы с dom, поток пользовательского интерфейса не существует. (Чтобы понять концепцию каждого потока, обратитесь к потоку в среде браузера)
Недостатком одиночного потока в операционной среде браузера является то, что он блокирует выполнение страницы.
Итак, node как серверная служба, каковы плюсы и минусы однопоточности?
преимущество:
- Избегайте накладных расходов на частое создание и переключение процессов, повышая скорость выполнения.
- Маленький след
- Безопасность потоков: не нужно беспокоиться о сбое программы, вызванном чтением и записью одной и той же переменной несколькими потоками одновременно. недостаток:
- Он не подходит для операций с интенсивным использованием ЦП, таких как большое количество вычислений и сжатие, которые вызовут блокировку.
Контур событий под узлом
Общее или неизменное кольцо событий, открытость, очередь сообщений, API. Отличается, очередь сообщений под Node отличается.
Анализ очереди сообщений под узлом- Выделить очереди сообщений для микрозадач, таймеров, io, setImmidiate соответственно
- Сначала проверьте очередь таймера, если есть какой-либо контент, затем очистите его все
- В процессе перехода из очереди времени в очередь ввода-вывода проверить микрозадачу, если есть ситуация микрозадача.
- Выполнение очереди ввода-вывода завершено, и если в очереди проверки есть содержимое, оно будет выполнено. В противном случае продолжайте проверять очередь таймера.
- полный замкнутый цикл
Начните с темы и почувствуйте разницу между средой узла и средой браузера.
setTimeout(() => {
console.log('timeout1');
Promise.resolve().then(() => {
console.log('promise');
});
}, 0)
setTimeout(() => {
console.log('timeout2');
}, 0)
Результат в браузере: timeout1 обещание timeout2
Результат под узлом: обещание timout1 timeout2
Микрозадачи и макрозадачи
Что такое микрозадачи и макрозадачи в среде узла
Задача макроса: setTimeout setImmediate
Микрозадача: Promise.then process.nextTick
Тема 3 может хорошо проанализировать выполнение задачи в среде узла
Запуск процесса в среде узла
- Сначала встретите две задачи макроса и поместите их в очередь времени.
- Когда первая макрозадача в очереди времени выполнения имеет значение timeout1, она встречает обещание микрозадачи и помещает ее в очередь микрозадач.
- В это время очередь времени не была очищена, и она продолжает выполнять и завершать все задачи в очереди времени. выполнить тайм-аут2
- Проверяйте микрозадачи при переключении очередей ввода-вывода и выполняйте четкие микрозадачи. Выполнять обещания.
Запуск процесса в среде браузера - Сначала встретите две задачи макросов и поместите их в очередь задач макросов.
- Когда первая макрозадача в очереди времени выполнения имеет значение timeout1, она встречает обещание микрозадачи и помещает ее в очередь микрозадач.
- timout1 выполняет и завершает микрозадачу проверки, и если контент есть, он будет очищен, а обещание будет выполнено.
- После очистки микрозадачи выполните макрозадачу. выполнить тайм-аут2
注意
: Это также микрозадача, process.nextTick, которую лучше, чем promise.then выполнять первой.
Promise.resolve().then(() => {
console.log('then')
})
process.nextTick(() => {
console.log('nextTick')
});
//nextTick then
注意
: Это тоже задача макроса. Порядок выполнения setTimeout и setImediate не определен и зависит от скорости выполнения стека выполнения.
setImmediate(function () {
console.log('setImmediate')
});
setTimeout(function () {
console.log('setTimeout')
}, 0); // ->4
Но есть фиксированный вывод в следующих сценариях
let fs = require('fs');
fs.readFile('./gitignore', function () { // io的下一个事件队列是check阶段
setImmediate(function () {
console.log('setImmediate')
});
setTimeout(function () {
console.log('setTimeout')
}, 0); // ->4
})
Чтобы дать подсказку, чтение файла является операцией ввода-вывода.После выполнения ввода-вывода сначала проверьте, а затем проверьте очередь времени после проверки или отсутствия проверки содержимого. Затем результаты остаются для вашего собственного анализа.
Суммировать
Я надеюсь, что эта статья поможет вам впервые получить четкое общее представление о js, а также упорядочить мои собственные знания. Возможно мое понимание поверхностно, есть ошибки, надеюсь вы поможете мне исправить.