Есть ли разница между вызовом setTimeout с нулевой задержкой и без тайминга в JavaScript
Что проверяют
Знаете ли вы, что setTimeout(fn) и setTimeout(fn, 0) одно и то же, и понимаете ли, что ноль не значит «сразу». Следом почти всегда дают код с Promise.then, setTimeout и console.log и просят назвать порядок вывода.
Как отвечать
Короткий ответ: разницы нет. Если задержку не передать, она считается нулевой, так же обрабатываются undefined, отрицательное число и NaN. Дальше раскройте, что на самом деле означает ноль:
- это макрозадача: колбэк попадает в очередь задач и выполнится только после того, как опустеет стек вызовов и отработают все микрозадачи (
Promise.then,queueMicrotask,MutationObserver). До него браузер может успеть перерисовать страницу; - ноль это минимум, а не гарантия: по спецификации HTML после пяти вложенных таймеров задержка меньше 4 мс поднимается до 4 мс, поэтому цепочка
setTimeout(tick, 0)быстрее не станет; - фоновые вкладки: браузеры замедляют таймеры в неактивных вкладках до раза в секунду и реже;
- Node.js: задержка меньше 1 мс превращается в 1 мс, поэтому порядок
setTimeout(fn, 0)иsetImmediate(fn)в главном модуле не определён, а внутри колбэка ввода-выводаsetImmediateсработает первым.
Зачем нулевой таймаут вообще нужен: отдать управление, чтобы браузер обработал ввод и отрисовку, разбить длинную задачу на куски, выполнить код после текущего обработчика события. Для этого в Chromium есть scheduler.yield() и scheduler.postTask(), а для анимаций правильный инструмент requestAnimationFrame.
Аргументы для колбэка идут третьим и дальше параметрами, поэтому setTimeout(fn, undefined, arg) тоже сработает с нулевой задержкой.
Где спотыкаются
Отвечают на другой вопрос: сравнивают setTimeout с прямым вызовом функции. Это полезно, но спрашивали про пропущенный аргумент задержки.
Считают, что колбэк с нулём выполнится раньше промиса. Микрозадачи всегда идут первыми, и при бесконечной цепочке промисов таймер не выполнится вообще.
Используют setTimeout(fn, 0), чтобы «дождаться, пока React обновит DOM». Это работает случайно, правильные инструменты здесь эффекты, flushSync или requestAnimationFrame.