js операционный механизм цикла событий

Node.js JavaScript браузер Promise

Цикл событий, цикл событий, процесс потока. Эти концепции могут сбивать с толку студентов, которые плохо знакомы с внешним интерфейсом. А средой выполнения для запуска js-кода является не только браузер, но и node. Поэтому обработка Event Loops в разных средах становится разной, что очень легко спутать. Если у вас есть такие сомнения. Следующее даст вам ясное объяснение.

Концепция кардинга

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

Основные понятия процессов и потоков

Возьмите понятия из учебника:

1. Планирование: поток — это основная единица планирования и распределения, а процесс — основная единица владения ресурсами;

2. Параллелизм: не только процессы могут выполняться одновременно, но и несколько потоков одного и того же процесса могут выполняться одновременно;

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

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

Отношения между процессами и потоками:

  1. Поток может принадлежать только одному процессу, а процесс может иметь несколько потоков, но по крайней мере один поток;
  2. Ресурсы выделяются процессу, и все потоки одного и того же процесса совместно используют все ресурсы процесса;
  3. Процессор назначается потоку, то есть поток действительно выполняется на процессоре;
  4. Потоки нуждаются в совместной синхронизации во время процесса выполнения. Потоки различных процессов должны быть синхронизированы посредством обмена сообщениями. Поток — это исполнительная единица внутри процесса и планируемая сущность внутри процесса.
    На первый взгляд это может не понравиться. Но с самой основной идеей процесс может иметь несколько потоков, и потоки могут взаимодействовать друг с другом. Этих двух пунктов достаточно, чтобы вы поняли знание последующего цикла событий.

Процессы, потоки и циклы событий в браузере

процесс браузера

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

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

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

Из рисунка видно, что желтая округлая коробка заворачивается в процессе. Синие прямоугольные прямоугольники — это все потоки, содержащиеся в механизме рендеринга браузера (ядре браузера). В соответствии с приведенной выше концепцией «процесс может иметь несколько потоков, но по крайней мере один поток». Первые три процесса только что были упомянуты в 1-3. Было представлено, что многие из наших интерфейсных операций фактически обрабатываются в движке рендеринга браузера 3. Настоящая работа — это нить. В соответствии с приведенной выше концепцией «процессор назначается потоку, то есть поток действительно выполняется на процессоре».

Потоки ядра браузера

Затем посмотрите, какие потоки включены в движок браузера (процесс)

  • Поток рендеринга пользовательского интерфейса Отвечает за рендеринг интерфейса браузера, анализ 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 выглядит следующим образом.

В это время возьмите несколько вопросов и посмотрите на него, чтобы было понятнее Тема 1:

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 как серверная служба, каковы плюсы и минусы однопоточности?
преимущество:

  1. Избегайте накладных расходов на частое создание и переключение процессов, повышая скорость выполнения.
  2. Маленький след
  3. Безопасность потоков: не нужно беспокоиться о сбое программы, вызванном чтением и записью одной и той же переменной несколькими потоками одновременно. недостаток:
  4. Он не подходит для операций с интенсивным использованием ЦП, таких как большое количество вычислений и сжатие, которые вызовут блокировку.

Контур событий под узлом

Общее или неизменное кольцо событий, открытость, очередь сообщений, 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, а также упорядочить мои собственные знания. Возможно мое понимание поверхностно, есть ошибки, надеюсь вы поможете мне исправить.

использованная литература

  1. От многопроцессорности браузера до однопоточности JS — наиболее полное сочетание операционного механизма JS.
  2. Подробное объяснение потоков и процессов Node.js