Цикл событий в браузере
Использованная литература:Модель параллелизма и цикл обработки событий — MDN
Подробное объяснение механизма работы JavaScript: снова поговорим о цикле событий @ Учитель Руан
Все мы знаем, что JavaScript является однопоточным, а это означает, что в каждый момент времени можно выполнять только одну операцию. Это связано с тем, что JavaScript в основном используется для управленияDOM
Да, если он станет многопоточным, браузер запутается и не будет знать, кого слушать. Но хотя js и однопоточный, он может полностью имитировать многопоточность, полагаясь наEvent Loop
.
Мы все знаем кодовые точки в js同步
а также异步
,Так называемый异步
На самом деле, он не будет блокировать наш основной поток и ждать выполнения кода основного потока перед выполнением.callback setTimeout setInterval Promise ...
Все это нам знакомо异步
код
Как показано на рисунке, память в js делится на堆内存(heap)
а также栈内存(stack)
, 堆内存
То, что существует, это то, что мы декларируемobject
тип данных,栈内存
Хранится в基本数据类型
так же как函数执行时
рабочее пространство. наш同步
код помещается в执行栈
а как насчет асинхронного кода? Браузер будетdom事件 ajax setTimeout
Подождите, пока асинхронный код будет поставлен в очередь, подождите执行栈
Код в очереди будет выполнен только после того, как код в очереди будет выполнен.Это немного похоже на режим публикации-подписки?
console.log(1);
setTimeout(() => {
console.log(2);
}, 0);
console.log(3);
Согласно тому, что я сказал ранее, setTimeout будет помещен в очередь и не будет выполняться до тех пор, пока не будет выполнен код в стеке выполнения, поэтому он выведет1, 3, 2
но异步
Код тоже отличается:
console.log(1)
setTimeout(() => {
console.log(2)
}, 0)
Promise.resolve().then(() => {
console.log(3)
})
вывод всегда1, 3, 2
, то естьpromise
существуетsetTimeout
выполнял раньше. Это потому что异步任务
разделен на微任务(microtask)
а также宏任务(task)
, порядок выполнения执行栈中的代码 => 微任务 => 宏任务
.
стек выполнения
-
执行栈
Код всегда выполняется первым
Микрозадачи:promise MutationObserver...
- когда
执行栈
После того, как код будет выполнен, он будет выполнен宏任务队列
увидеть раньше微任务队列
Есть ли какая-то задача, если есть, будет сначала微任务队列
Задачи в宏任务队列
Задача макроса (task):setTimeout setInterval setImmediate(IE专用) messageChannel...
- ждать
执行栈
а также微任务队列
Он будет выполняться после завершения всех исполнений, и после выполнения каждого宏任务
После этого я пойду и посмотрю微任务队列
Есть ли новые добавленные задачи? Если да, то они будут добавлены первыми微任务
Задача в очереди очищается перед переходом к следующей宏任务
setTimeout(() => {
console.log('timeout1')
Promise.resolve().then(() => {
console.log('promise1')
})
Promise.resolve().then(() => {
console.log('promise2')
})
}, 100)
setTimeout(() => {
console.log('timeout2')
Promise.resolve().then(() => {
console.log('promise3')
})
}, 200)
- первые два
setTimeout
Поместить в очередь задач макросов - когда первый
setTimeout1
Когда время выполнения истекло, сначала напечатайте timeout1, а затем поместите его в очередь микрозадач.promise1
а такжеpromise2
- когда первый
setTimeout1
После завершения выполнения он перейдет к очереди микрозадач, чтобы проверить, не пуста ли она.Он обнаружил, что есть дваpromise
, поставлю дваpromise
Выполнить по порядку, а затем перейти к следующей задаче макроса - два
promise
После завершения выполнения задач в очереди микрозадач не будет, а следующая задача будет выполняться в задаче макроса.setTimeout2
- когда
setTimeout2
При выполнении выводить сначала таймаут2, а потом вставлять в очередь микрозадачи еще одинpromise2
- когда
setTimeout2
После того, как выполнение будет завершено, оно отправится в очередь микрозадач, чтобы проверить и обнаружить, что существует promise3, которыйpromise3
воплощать в жизнь - будет печатать последовательно
timeout1 promise1 promise2 timeout2 promise3
Цикл событий в узле
Использованная литература:libuv Документация узла
Все мы знаем, что Node.js — это среда выполнения JavaScript, основанная на движке Chrome V8, то есть она позволяет запускать js на стороне сервера. Но цикл событий в Node моделируется с помощью libuv, который назначает разные задачи разным потокам для формирования цикла событий и возвращает результат выполнения задачи в механизм V8 асинхронным образом.
- Микрозадачи в узле:
process.nextTric promise setImmediate...
- Задача макроса в узле:
setTimeout setInterval...
- таймеры: выполнять обратные вызовы, срок действия которых истекает в setTimeout() и setInterval().
- Обратные вызовы ввода-вывода: небольшое количество обратных вызовов ввода-вывода в предыдущем раунде цикла будет отложено до этой стадии раунда.
- бездействие, подготовка: только для внутреннего использования
- опрос: самый важный этап, выполнить обратный вызов ввода-вывода, проверить, есть ли таймеры с истекшим сроком действия, которые будут заблокированы на этом этапе при соответствующих условиях
- проверка: выполнить обратный вызов setImmediate
- обратные вызовы закрытия: выполнить обратный вызов события закрытия, например socket.on("close",func)
Цикл событий в узле будет очищать очередь микрозадач при каждом переключении очереди, а также выполнять текущую очередь.При переходе на следующий этап проверяйте, есть ли задачи в микрозадачах.
setTimeout(() => {
console.log('timeout1')
Promise.resolve().then(() => {
console.log('promise1')
})
Promise.resolve().then(() => {
console.log('promise2')
})
}, 0)
setTimeout(() => {
console.log('timeout2')
Promise.resolve().then(() => {
console.log('promise3')
})
}, 0)
- первые два
setTimeout
Поместить в очередь задач макросов - когда первый
setTimeout1
Когда время выполнения истекло, сначала напечатайте timeout1, а затем поместите его в очередь микрозадач.promise1
а такжеpromise2
- когда первый
setTimeout1
После завершения выполнения переходите к следующемуsetTimeout2
- когда
setTimeout2
При выполнении выводить сначала таймаут2, а потом вставлять в очередь микрозадачи еще одинpromise2
- Текущая очередь макрозадач очищается и переходите к следующему этапу, чтобы проверить, есть ли задачи в очереди микрозадач.
- Очистить очередь микрозадач
- Выполняется в среде узла, будет печататься последовательно
timeout1 timeout2 promise1 promise2 promise3