Как будет вести себя вкладка при рекурсивном создании макротасок
Что проверяют
Понимаете ли вы, когда в цикле событий браузер успевает отрисовать страницу и обработать ввод. Вопрос с подвохом: многие ждут зависания, а его не будет. Следом почти всегда спрашивают, что изменится, если заменить setTimeout на Promise.resolve().then().
Как отвечать
Цикл событий берёт одну макротаску, выполняет её, полностью опустошает очередь микротасок и только после этого получает возможность отрисовать кадр и взять следующую задачу, например клик. Отсюда поведение:
- рекурсивный
setTimeout(fn, 0): между задачами браузер рендерит и обрабатывает события, вкладка остаётся отзывчивой. После пятого уровня вложенности спецификация HTML поднимает минимальную задержку до 4 мс, так что цепочка срабатывает не чаще примерно 250 раз в секунду: процессор нагружен, но интерфейс не залипает; - фоновая вкладка: браузеры душат таймеры скрытых вкладок, Chrome до одного срабатывания в секунду, а у долго скрытой вкладки цепочки таймеров выравнивает ещё реже;
MessageChannelилиpostMessage: макротаски без ограничения в 4 мс, поэтому планировщики вроде React используют именно их. Отрисовка между ними всё равно возможна;- рекурсивные микротаски (
queueMicrotask,.then()): очередь не кончается, до отрисовки дело не доходит, вкладка зависает так же, как отwhile (true).
Отдельно назовите две настоящие проблемы. Первая: длинная сама задача. Если каждая макротаска работает по 200 мс, интерфейс дёргается, и работу нужно дробить на куски короче 50 мс, например через scheduler.yield() там, где он поддерживается. Вторая: разветвление. Если каждая задача ставит две новые, очередь растёт экспоненциально и съедает память.
Где спотыкаются
Путают макро- и микротаски и уверенно отвечают, что вкладка зависнет от рекурсивного setTimeout.
Не знают про ограничение в 4 мс и троттлинг таймеров в фоне, поэтому не могут объяснить, почему фоновый код вдруг замедлился.
Советуют «перенести тяжёлую работу в микротаски, чтобы не блокировать поток». Микротаски блокируют отрисовку сильнее, а для тяжёлых вычислений есть Web Worker.