Влияет ли добавление async/await на порядок вывода в консоли?
Что проверяют
Знаете ли вы, как устроен event loop: где заканчивается синхронная часть async-функции и куда уходит продолжение после await. Обычно после ответа дают задачку с setTimeout, Promise.then и await вперемешку и просят назвать порядок вывода.
Как отвечать
Короткий ответ: да, влияет, но предсказуемо. Опирайтесь на три правила:
- тело async-функции начинается синхронно: всё до первого
awaitвыполняется сразу при вызове, как в обычной функции; awaitвсегда уступает поток: дажеawait nullоткладывает остаток функции в очередь микрозадач, и код после вызова функции успевает выполниться раньше;- микрозадачи раньше макрозадач: продолжения после
awaitи колбэки.thenвыполняются, как только опустеет стек вызовов, аsetTimeout(fn, 0)ждёт следующего витка цикла событий.
Пример, который стоит уметь разобрать вслух:
console.log(1);
setTimeout(() => console.log(2), 0);
(async () => {
console.log(3);
await null;
console.log(4);
})();
Promise.resolve().then(() => console.log(5));
console.log(6);Вывод: 1, 3, 6, 4, 5, 2. Четвёрка раньше пятёрки, потому что продолжение после await встало в очередь микрозадач первым. Двойка последняя, это макрозадача.
Отдельно скажите, что сам по себе async без await порядок логов внутри функции не меняет. Но функция теперь возвращает промис, и всё, что вешается на него через .then, выполнится после синхронного кода.
Где спотыкаются
Думают, что await блокирует всю программу. Он приостанавливает только текущую функцию, вызывающий код продолжает работу.
Считают, что async-функция целиком выполняется асинхронно, и ставят лог из её начала после внешнего console.log.
Пишут items.forEach(async (item) => { await save(item); }) и ждут, что код после цикла дождётся сохранения. forEach возвращённые промисы игнорирует, нужен for...of с await или Promise.all.