Вызовите setTimeout без задержки

Довольно часто см. в JavaScript-библиотеке код следующим образом:

setTimeout(function() {
    ...
}, 0);

Я хотел бы знать, зачем использовать такой код оболочки.

Ответ 1

Очень упрощено:

Браузеры однопоточные, и этот единственный поток (поток пользовательского интерфейса) распределяется между механизмом рендеринга и движком js.

Если вещь, которую вы хотите сделать, занимает много времени (мы говорим о циклах здесь, но все же), она может остановить (paus) рендеринг (поток и краска).

В браузерах также существует "Ведро", где все события сначала задерживаются, когда поток пользовательского интерфейса выполняется с тем, что он делает. Как только поток выполняется, он смотрит в ведро и сначала берет задачу.

Используя setTimeout, вы создаете новую задачу в корзине после задержки и позволяете потоку справляться с ней, как только она доступна для большей работы.

История:

После задержки 0 мс создать новую задачу функции и положите его в ведро. В этот момент поток пользовательского интерфейса занят делать что-то еще, и есть еще одна задача в ковше уже. После 6ms поток доступен и получает задачу infront твой, хорошо, ты следующий. Но что? Это была одна огромная вещь! В нем есть был как foreeeeeever (30 мс)!

Наконец, теперь поток выполняется с этим и приходит и получает ваш Задача.

Большинство браузеров имеют минимальную задержку, которая больше 0, поэтому установка 0 в качестве задержки означает: Поместите эту задачу в корзину как можно скорее. Но говорить UA, чтобы поместить его в ведро ASAP, не является гарантией того, что он выполнит в тот момент. Ведро похоже на почтовое отделение, может быть, есть еще одна очередь других задач. Почтовые ветки также однопоточные, и только один человек помогает в решении всех задач... извините клиентов за свои задачи. Ваша задача должна попасть в очередь, как и все остальные.

Если браузер не использует собственный тикер, он использует циклы тиков ОС. У старых браузеров были минимальные задержки между 10-15 мс. HTML5 указывает, что если время задержки меньше 4 мс, UA должен увеличить его до 4 мс. Это называется согласованный в браузерах, выпущенных в 2010 году и далее.

Подробнее см. Как работает JavaScript Timers от Джона Ресига.

Изменить: Также см. Какая черта в цикле событий? Филипп Робертс из JSConf EU 2014 Это обязательный просмотр для всех людей, затрагивающих внешний код.

Ответ 2

Есть несколько причин, почему вы это сделаете

  • Существует действие, которое вы не хотите запускать сразу, но хотите запустить в ближайшее ближайшее время.
  • Вы хотите разрешить другим ранее зарегистрированным обработчикам из setTimeout или setInterval для запуска

Ответ 3

Помимо предыдущих ответов я хотел бы добавить еще один полезный сценарий, о котором я могу думать: "побег" из блока try-catch. Задержка setTimeout изнутри блока try-catch будет выполняться вне блока, и любое исключение будет распространяться в глобальной области.

Возможно, лучший пример сценария: на сегодняшний день JavaScript с более распространенным использованием так называемых Deferreds/Promises для асинхронных обратных вызовов, которые вы часто выполняете внутри try-catch. Отложенные /Promises завершают обратный вызов в try-catch, чтобы иметь возможность обнаруживать и распространять исключение как ошибку в асинхронной цепочке. Все это хорошо для функций, которые должны быть в цепочке, но рано или поздно вы будете "сделаны" (т.е. выбрали все свои ajax) и хотите запустить простой неасинхронный код, где вы не хотите, чтобы исключения были "скрытый". AFAIK Dojo, Kris Kowal Q, MochiKit и Google Closure lib используют упаковку try-catch (но не jQuery).

(В несколько нечетных случаев я также использовал технику для перезапуска кода в одноэлементном стиле, не вызывая рекурсии. Я делаю перезапуск-перезапуск в том же цикле).

Ответ 4

Если вы хотите выполнить остальную часть своего кода, не дожидаясь предыдущего, вы должны добавить его в анонимный метод, переданный функции setTimeout. В противном случае ваш код будет ждать, пока не будет выполнено предыдущее

Пример:

function callMe()
{
   for(var i = 0; i < 100000; i++)
     {
       document.title = i;
     }
} 

var x = 10;
setTimeout(callMe, 0);

var el = document.getElementById('test-id');
el.innerHTML = 'Im done before callMe method';

Вот почему я использую его.

Ответ 5

Чтобы разрешить выполнение любых ранее заданных тайм-аутов.