Почему setTimeout (fn, 0) иногда полезен? - PullRequest
789 голосов
/ 23 апреля 2009

Недавно я столкнулся с довольно неприятной ошибкой, когда код динамически загружал <select> через JavaScript. Это динамически загруженное <select> имело предварительно выбранное значение. В IE6 у нас уже был код для исправления выбранного <option>, поскольку иногда значение selectedIndex <select> не синхронизировалось бы с выбранным атрибутом index *1007*, как показано ниже:

field.selectedIndex = element.index;

Однако этот код не работал. Даже если поле selectedIndex было установлено правильно, в итоге будет выбран неправильный индекс. Однако, если я вставлю оператор alert() в нужное время, будет выбран правильный вариант. Подумав, что это может быть проблема с синхронизацией, я попробовал что-то случайное, что раньше видел в коде:

var wrapFn = (function() {
    var myField = field;
    var myElement = element;

    return function() {
        myField.selectedIndex = myElement.index;
    }
})();
setTimeout(wrapFn, 0);

И это сработало!

У меня есть решение для моей проблемы, но мне непросто, что я не знаю точно, почему это решает мою проблему. У кого-нибудь есть официальное объяснение? Какую проблему с браузером я избегаю, вызывая свою функцию «позже», используя setTimeout()?

Ответы [ 17 ]

3 голосов
/ 21 июня 2012

Другая вещь, которую это делает, это выдвигает вызов функции в конец стека, предотвращая переполнение стека, если вы рекурсивно вызываете функцию. Это имеет эффект цикла while, но позволяет механизму JavaScript запускать другие асинхронные таймеры.

2 голосов
/ 14 марта 2013

Ответы о циклах выполнения и рендеринге DOM до завершения какого-либо другого кода верны. Нулевое время ожидания в JavaScript помогает сделать код псевдо-многопоточным, даже если это не так.

Я хочу добавить, что значение BEST для межбраузерного / межплатформенного тайм-аута на ноль секунд в JavaScript на самом деле составляет около 20 миллисекунд вместо 0 (нуля), потому что многие мобильные браузеры не могут регистрировать тайм-ауты меньше 20 миллисекунд ограничения часов на чипах AMD.

Кроме того, длительные процессы, которые не связаны с манипулированием DOM, должны теперь отправляться веб-работникам, поскольку они обеспечивают истинное многопоточное выполнение JavaScript.

1 голос
/ 02 сентября 2015

setTimout on 0 также очень полезен в шаблоне установки отложенного обещания, которое вы хотите вернуть сразу:

myObject.prototype.myMethodDeferred = function() {
    var deferredObject = $.Deferred();
    var that = this;  // Because setTimeout won't work right with this
    setTimeout(function() { 
        return myMethodActualWork.call(that, deferredObject);
    }, 0);
    return deferredObject.promise();
}
1 голос
/ 23 апреля 2009

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

1 голос
/ 15 сентября 2018

Проблема заключалась в том, что вы пытались выполнить операцию Javascript на несуществующем элементе. Элемент еще не был загружен, и setTimeout() дает больше времени для загрузки элемента следующими способами:

  1. setTimeout() заставляет событие быть асинхронным , поэтому выполняется после всего синхронного кода, давая вашему элементу больше времени для загрузки. Асинхронные обратные вызовы, такие как обратный вызов в setTimeout(), помещаются в очередь событий и помещаются в стек с помощью цикла событий после того, как стек синхронного кода пуст.
  2. Значение 0 для ms в качестве второго аргумента в функции setTimeout() часто немного выше (4-10 мс в зависимости от браузера). Это немного более высокое время, необходимое для выполнения обратных вызовов setTimeout(), вызвано количеством 'тиков' (когда тик помещает обратный вызов в стек, если стек пуст) цикла обработки событий. Из-за производительности и времени автономной работы количество тактов в цикле событий ограничено определенной величиной меньше , чем 1000 раз в секунду.
1 голос
/ 14 декабря 2012

Некоторые другие случаи, когда setTimeout полезен:

Вы хотите разбить длительный цикл или вычисления на более мелкие компоненты, чтобы браузер не зависал и не говорил «Сценарий на странице занят».

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

0 голосов
/ 22 января 2018

Javascript является однопоточным приложением, поэтому не позволяет одновременно запускать функции, поэтому для достижения этого используются циклы событий. Так что именно то, что setTimeout (fn, 0) делает это, помещается в задание, которое выполняется, когда ваш стек вызовов пуст. Я знаю, что это объяснение довольно скучно, поэтому я рекомендую вам просмотреть это видео, оно поможет вам, как все работает в браузере. Проверьте это видео: - https://www.youtube.com/watch?time_continue=392&v=8aGhZQkoFbQ

...