Механизм цикла событий браузера (цикл событий)

JavaScript браузер C++ Ajax

JS однопоточный

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

Хотя JS выполняется в одном потоке в браузере, браузер управляется событиями.Многие действия в браузере являются асинхронными (асинхронизированными), а события создаются и помещаются в очередь выполнения. Многие асинхронные действия в браузере завершаются тем, что браузер открывает новый поток.Браузер реализует как минимум три резидентных потока:

  • Поток движка JS
  • Поток рендеринга графического интерфейса
  • поток триггера события

JS-движок

Движок JavaScript — это виртуальная машина, которая специализируется на обработке сценариев JavaScript. Обычно она подключается к веб-браузеру. Например, наиболее известным является движок V8 браузера Chrome. Как показано на рисунке ниже, движок JS в основном состоит из двух компонентов:

  • Куча - где происходит выделение памяти
  • Стек — при вызове функции она формирует кадр стека (кадр)
    image

стек выполнения

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

image
Возьмем простой пример:

function bar() {
console.log('bar');
}

function foo() {
console.log('foo');
bar();
}

foo();

Изменения в стеке во время выполнения:

image

цикл событий

Википедия определяет это так:

«Цикл событий — это программная конструкция, которая ожидает и отправляет события или сообщения в программе».

Проще говоря, это создание в программе двух потоков: один отвечает за работу самой программы, называемый «главным потоком»; другой отвечает за связь между основным потоком и другими процессами (в основном различными I /O), называемый «поток цикла событий» (можно перевести как «поток сообщений»).

image

Цикл событий и очередь задач

Цикл событий можно просто описать так:

  1. Функция помещается в стек.Когда асинхронная задача выполняется в стеке, она передается в WebAPI, а затем синхронная задача выполняется до тех пор, пока стек не станет пустым;
  2. В течение этого периода WebAPI завершает это событие и помещает функцию обратного вызова в CallbackQueue для ожидания;
  3. Когда стек выполнения пуст, цикл событий помещает задачу из очереди обратного вызова в стек и возвращается к шагу 1.
    image
  • Цикл событий реализуется средой размещения javascript (например, браузером);
  • WebAPI — это созданные браузером потоки, реализованные на C++, которые обрабатывают асинхронные события, такие как события DOM, HTTP-запросы, таймеры и т. д.;
  • Модель параллелизма в JavaScript основана на «цикле событий»;
  • Очередь обратного вызова (очередь событий или очередь сообщений), в которой хранятся функции обратного вызова для асинхронных задач.

Рассмотрим пример асинхронного выполнения функции:

var start=new Date();
setTimeout(function cb(){
    console.log("时间间隔:",new Date()-start+'ms');
},500);
while(new Date()-start<1000){};
  1. Функция main(Script) помещается в стек, а начальная переменная инициализируется
  2. стек setTimeout, стек, бросил WebAPI, время начала 500 мс;
  3. Цикл while помещается в стек и начинает блокироваться на 1000 мс;
  4. Через 500 мс WebAPI помещает cb() в очередь задач, в то время как цикл while все еще находится в стеке, а cb() ожидает;
  5. Еще через 500 мс цикл while выполняется и извлекается из стека, всплывает main(), стек в это время пуст, цикл событий, cb() входит в стек, log() проталкивает стек, выводит 'time interval : 1003 мс, извлекает стек, cb() извлекает из стека

Макрозадачи и микрозадачи

По сути, то, что мы сказали выше, это макрозадачи (Macrotasks), но в js есть еще и микрозадача очереди (Microtasks).

макро-задача (задача): Цикл событий имеет одну или несколько очередей задач. Источник задачи очень широк, например, ajax onload и click события. В основном различные события, которые мы часто связываем, являются источниками задачи задачи, а также операции базы данных (IndexedDB). Следует отметить, что setTimeout, setInterval и setImmediate также задача задачи источник. Подводя итог, источник задачи задачи:

  • setTimeout
  • setInterval
  • setImmediate
  • I/O
  • UI rendering

Micro-Task (задание): очередь MicroTask несколько похожа на очередь задач. Оба являются в первую очередь, в первую очередь. Указанный источник задач предоставляет задачи. Разница в В контуре события есть только одна очередь микрозазки. Кроме того, сроки исполнения микрозазки также отличаются от макрозащитников.

  • process.nextTick
  • promises
  • Object.observe
  • MutationObserver

Так в чем же разница между макрозадачами и микрозадачами?
В качестве простого примера предположим, что код тега скрипта выглядит следующим образом:

Promise.resolve().then(function promise1 () {
       console.log('promise1');
    })
setTimeout(function setTimeout1 (){
    console.log('setTimeout1')
    Promise.resolve().then(function  promise2 () {
       console.log('promise2');
    })
}, 0)

setTimeout(function setTimeout2 (){
   console.log('setTimeout2')
}, 0)

рабочий процесс:

Код в скрипте отображается как задача и помещается в очередь задач.

Цикл 1:

  • [очередь задач: скрипт; очередь микрозадач:]
  1. Возьмите задачу сценария из очереди задач и поместите ее в стек для выполнения.
  2. promise1 указан как микрозадача, setTimeout1 указан как задача, а setTimeout2 указан как задача.
  • [очередь задач: setTimeout1 setTimeout2; очередь микрозадач: promise1]
  1. После выполнения задачи скрипта выполняется контрольная точка микрозадачи, а promise1 очереди микрозадач вынимается и выполняется.

Цикл 2:

*[очередь задач: setTimeout1 setTimeout2; очередь микрозадач:] 4. Возьмите setTimeout1 из очереди задач, поместите его в стек для выполнения и перечислите promise2 как микрозадачу.

  • [очередь задач: setTimeout2; очередь микрозадач: promise2]
  1. Выполните контрольную точку микрозадачи и выньте promise2 из очереди микрозадач для выполнения.

Цикл 3:

  • [очередь задач: setTimeout2; очередь микрозадач:]
  1. Возьмите setTimeout2 из очереди задач и поместите его в стек для выполнения. 7. После выполнения задачи setTimeout2 выполнить контрольную точку микрозадачи.
  • [очередь задач:; очередь микрозадач:]

image

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

Обновите рендеринг в петле события (рендеринг обновления)

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