предисловие
Причина написания этой статьи в том, что я видел, как все в группе обсуждали эту часть контента. Я мало что знаю об этой части. Я написал эту статью, когда у меня чесались руки. Многие новички тоже мало знают об этом. Половина из них нашли это хлопотным и сложным, поэтому они просто сдались. Я изначально планировал написать ее после теста операционной системы, но снова столкнулся с классом ЦП... Так что эта статья писалась с перерывами на протяжении многих дней.
Event Loop
Проще говоря, цикл событий — это регулирование порядка выполнения кода JS (алгоритм планирования задач)
Взгляните на две фотографии
JS engine
via: sessionstack
JS runtime
via: sessionstack
ПРИМЕЧАНИЕ:
Веб-воркер или iframe из разных источников имеют собственный стек, кучу и очередь сообщений. Две разные среды выполнения могут взаимодействовать только через метод postMessage. Если другая среда выполнения прослушивает событие сообщения, этот метод добавляет к нему сообщение.
HTML Eventloop
Это изображение представляет собой визуализацию цикла событий в организации whatwg для разработки спецификации HTML.
Обычно мы пишем веб-код сJS runtimeиметь дело с
синхронный код
Несомненно, выполнено в порядке
console.log(2); // 非异步代码
console.log(3); // 非异步代码
Очевидно, что результат 2 3
неблокирующий код
Обычно делится на две задачи: макрозадачи и микрозадачи.
В цикле событий есть две разные очереди асинхронных задач: макрозадачи (задачи), очередь микрозадач.
-
К задачам макроса относятся: setTimeout, setInterval, setImmediate, ввод-вывод, рендеринг пользовательского интерфейса.
-
К микрозадачам относятся: Native Promise (некоторые реализованные Promise помещают метод then в задачу макроса), Object.observe (устарело), MutationObserver, MessageChannel
Каждый раз, когда вы начинаете выполнять фрагмент кода (тег скрипта), это макрозадача.
1. запуск событийного цикла
2, экстракты из задач очередь макрозайков выполнены
3. Микрозазорки очищают очередь для выполнения. Если есть задачи, которые не могут быть выполнены, нажмите на следующий раунд микрозапортов
4. Завершите цикл событий
Стоит отметить, что в стандарте HTML упоминается, что составная микрозадача может выполнять подзадачу при ее выполнении.Выполнение составной микрозадачи - очень сложная вещь.Я не нашел эту часть конкретного процесса выполнения в whatwg.
const p = Promise.resolve();
p.then(() => {
Promise.resolve().then(() => {
console.log('subTask');
});
}).then(() => {
console.log('compound microTasks');
});
// subTask
// compound microTasks
Само собой разумеется, что сначала выполняются два then из p, а microTask обнаруживается при выполнении обратного вызова функции then, что должно быть следующим раундом выполнения eventLoop, но результат действительно противоположный.
Реальный процесс выполнения кода браузером — это весь процесс ниже, а процесс восприятия кода написания — в красной рамке (поэтому, если кто-то спросит вас, какую макрозадачу и микрозадачу выполнить первой, не говорите еще раз микрозадачу)
setTimeout(() => {
console.log(123);
});
const p = Promise.resolve(
new Promise(resolve => {
setTimeout(() => {
resolve('p');
console.log(55);
}, 1000);
new Promise(resolve => {
resolve('p1');
}).then(r => console.log(r));
})
);
setTimeout(() => {
console.log(456);
});
p.then(r => console.log(r));
Вы можете сначала догадаться о порядке выполнения этого кода.Я думаю, что без приведенного выше вступления у многих здесь голова закружится. Но с приведенным выше введением и нашим пошаговым анализом вы обязательно поймете
- На первом этапе код выполняется для первой функции setTimeout, которая печатает 123 и помещает его в очередь задач макроса.
- Во второй части код выполняется для нового промиса в Promse.resolve, и ничего не делается... Продолжайте выполнять следующий код
- На третьем шаге выполняется код для setTimeout в новом промисе, а функция, которая выводит 55, помещается в очередь задач макроса.
- Четвертый шаг, код выполняется для нового промиса в новом промисе, выполняется конструктор, а затем функция then помещается в очередь микрозадач.
- Пятый шаг, код выполняется для первой функции setTimeout, которая печатает 456 и помещается в очередь задач макроса.
- Шестой шаг, код выполняется до последнего p.then и помещается в очередь микрозадач.
Число или переменная после имени функции — это то, что функция печатает, чтобы отличить функцию.
После сканирования этих кодов ситуация с каждой очередью задач выглядит следующим образом (обратите внимание, что setTimeout, предоставленный браузером в это время, проверит, соответствует ли каждая задача синхронизации времени, и если это так, она будет помещена в задачу очереди, поэтому функция обратного вызова времени 1000 мс не появляется в это время в macroTask) Затем, после выполнения кода синхронизации, начните выполнение макроса Task и micro Task, как описано выше.
Сначала выполняем микро Задание, вытаскиваем p.затем p1 и обнаруживаем, что оно исполняемое, печатаем p1, затем вынимаем p.затем p и обнаруживаем, что оно не выполнимо, то есть статус "ожидание", и этот раунд выполнение микро Задачи завершено. Начать выполнение макроса Task, вынуть setTimeout 123, найти, что он исполняемый (код синхронизации в это время выполнился), вывести 123, проверить выполнение микро Task, p.тогда p еще не исполняемый После того, как задача макроса выполняется в течение определенного периода времени, обнаруживается, что p.then p в микрозадаче является исполняемым, печатает и завершает цикл событий.
Таким образом, результат печати этого фрагмента кода
5
p1
123
456
55
p
Вы все сделали правильно? Это всего лишь небольшой случай. Асинхронная функция еще не добавлена. Давайте посмотрим на асинхронную функцию.
async/await
Когда асинхронная функция выполняет await, это на самом деле означает, что асинхронная функция должна отказаться от потока (лично я думаю, что это похоже на выполнение специальной функции, которая подтолкнет конец первого раунда очереди микрозадач), когда async After the функция или выражение после того, как оператор ожидания в функции будет выполнен, функция немедленно прекратит выполнение, и стек вызовов также будет отменен.Когда текущий цикл обработки событий будет завершен, он вернется для выполнения оставшегося кода.
Посмотрим, что скажет MDN
An async function can contain an await expression that pauses the execution of the async function and waits for the passed Promise's resolution, and then resumes the async function's execution and returns the resolved value.
Перевод заключается в том, что асинхронная функция может содержать выражение ожидания, которое приостанавливает выполнение асинхронной функции и ожидает завершения возвращенного промиса resovle/reject, затем возобновляет выполнение асинхронной функции и возвращает разрешенное значение.
После прочтения вы должны понять, почему выражения ожидания заставляют асинхронные функции создавать потоки, верно? (Если вы не отказываетесь от потока, лучше написать синхронный код и заблокировать весь следующий код), в сочетании с предыдущим циклом событий можно определить, что выражение ожидания должно дождаться завершения синтаксического анализа обещания. , а ожидание возобновляет выполнение асинхронной функции и нужно дождаться первого раунда выполнения.После микрозадачи ведь не каждая асинхронная функция напрямую возвращает не-промис-значение или сразу решенный промис, так что вам нужно дождаться раунда цикла событий после выполнения основного JS.
Выполнение какого кода блокируется ожиданием
await блокирует код, который в данный момент находится в области действия асинхронной функции.
Когда возобновить выполнение заблокированного кода?
Ответ заключается в возобновлении после каждого раунда выполнения микрозадачи, какой раунд зависит от того, когда будет разрешено возвращенное обещание.
Зайди в тему, посмотри async/await
async function b() {
console.log('1');
}
async function c() {
console.log('7');
}
async function a() {
console.log('2');
await b();
//console.log(3);
await c();
console.log(8);
}
a();
console.log(5);
Promise.resolve()
.then(() => {
console.log(4);
})
.then(() => {
console.log(6);
});
new Promise(resolve => {
setTimeout(() => resolve(), 1000);
}).then(() => console.log(55555555));
setTimeout(() => {
console.log(123);
});
С приведенным выше объяснением и следующим GIF процесс выполнения приведенного выше кода ясен с первого взгляда. Я не буду вдаваться в подробности, вы должны просто увидеть последовательность кода, который я выполняю пошагово (информация, выводимая при пошаговой отладке с использованием таймера, может отличаться от обычного выполнения)
Суммировать
-
Какая из них выполняется первой, макрозадача или микрозадача
macroTask выполняется первым (ведь стандарт так задан), а почему, я лично думаю, потому что macroTask — это событие, связанное с взаимодействием с пользователем, поэтому ему нужно вовремя среагировать
-
что делают асинхронные функции
Вы можете использовать выражения ожидания в асинхронных функциях, а возвращаемое значение асинхронных функций будет заключено в Promise.resolve (возвращаемое значение является объектом Promise, и объект возвращается напрямую)
// 验证
const p = new Promise(resolve => resolve());
console.log(p === Promise.resolve(p)); // true
-
что делает оператор ожидания
Предложение await сначала выполнит выражение, стоящее за ним (если выражение находится внутри функции, и функция встречает ожидание, в соответствии с той же процедурой будет выполнено), а затем заблокирует часть задней части кода, которая в настоящее время находится в области асинхронной функции.
-
Когда возобновить выполнение кода после оператора ожидания
Когда определенный цикл обработки событий после выполнения инструкции await, выполнение возобновляется (требуется дождаться завершения возвращенного разрешения промиса с правой стороны, а разрешение промиса может быть синхронным (новый промис) или асинхронным (.then ) , а обратный вызов then должен дождаться завершения цикла обработки событий)
использованная литература
| источник | Связь |
|---|---|
| Блог интерфейса IMWeb | imweb.io/ |
| MDN | developer.mozilla.org/en-US/ |
| Еженедельное интенсивное чтение переднего плана | GitHub.com/но он-поделиться/неделю… |
| sessionstack | blog.sessionstack.com/ |
| v8 Blog fastasync (китайская версия) | V8. чтобы иметь возможность /blog/fast-ah... |
| Tasks, microtasks, queues and schedules | Джейк Арчибальд.com/2015/tasks-… |
| Secrets of the JavaScript Ninja | live book.manning.com/#!/book/colors… |