Являются ли равные тайм-ауты, выполненные в Javascript?
Предположим, что я
setTimeout(foo, 0);
...
setTimeout(bar, 0);
Могу ли я быть уверенным, что foo начнет выполнение перед баром? Что, если вместо 0 я использую тайм-аут 1, 10 или 100 для бара?
Простые эксперименты показывают, что в случае равных значений таймаута цели таймаута выполняются в том же порядке, что и сами setTimeouts, но можно ли полагаться на это поведение?
Ответы
Ответ 1
Небезопасно полагаться на это поведение. Я написал тест script, в котором расписано несколько функций (и они, в свою очередь, также планируют ряд функций), все с использованием setTimeout (..., 0) и порядок, в котором вызывались функции, не был всегда совпадает с порядком, в котором setTimeout был вызван (по крайней мере, в Chrome 11, который я использовал для запуска script).
Вы можете увидеть/запустить script здесь: http://jsfiddle.net/se9Jn/
(script использует YUI для кросс-браузерной совместимости, но Y.later использует setTimeout внутри).
Обратите внимание, что если вы просто запустите script и посмотрите на консоль, вы, вероятно, не увидите оскорбительного заказа. Но если вы запустите script, переключитесь на другую вкладку, загрузите несколько страниц и вернитесь на тестовую страницу, вы увидите ошибки в обратных вызовах в консоли.
Если вам нужен гарантированный заказ, я бы рекомендовал планировать следующую функцию в конце предыдущей функции:
setTimeout(foo, 0);
...
function foo() {
...
setTimeout(bar, 0);
}
Ответ 2
Я прочитал исходный код Firefox и, по крайней мере, для этого браузера, есть гарантия последовательности тайм-аутов, которые указаны в неубывающем порядке. В противном случае все ставки отключены.
В частности, если в заданном контексте выполнения вы устанавливаете тайм-аут для n, а затем один для m, где n <= m, цели будут выполняться в том порядке, в котором установлены таймауты.
Но не верьте мне на слово. Я считаю, что реализация окна находится в nsGlobalWindow.cpp, и метод, который фактически решает, где тайм-ауты идут в очереди выполнения, называется InsertTimeoutIntoList. Похоже, что метод пересекает очередь назад, ища первый тайм-аут, который меньше или равен заданному тайм-ауту, и вставляет указанный таймаут после него.
Конечно, когда время ожидания установлено, текущее время часов добавляется к значению таймаута. Вот почему значения тайм-аута должны быть в неубывающем порядке для целей, которые должны выполняться последовательно.
Ответ 3
Короче говоря, не рассчитывайте на это. Посмотрите это.
Там много информации в этом цифра для переваривания, но понимание этого полностью даст вам лучшее реализация асинхронного Выполнение JavaScript выполняется.
Ответ 4
Ответ: Нет, порядок выполнения не гарантируется. Я иногда видел не-FIFO-заказ в chrome 40, особенно если я приостанавливаюсь в отладчике, пока ожидания не ожидаются. У меня также было редкое зрелище в дикой природе - это было единственное правдоподобное объяснение инцидента, который я исследовал.
Если вам нужен гарантированный порядок выполнения, вместо setTimeout(callback, 0)
вы можете сделать это:
var queue = [];
function handleQueue() {
queue.shift()();
}
function queueCallback(callback) {
queue.push(callback);
setTimeout(handleQueue, 0);
}
Теперь, для гарантированного foo
, bar
заказа вы можете:
queueCallback(foo);
...
queueCallback(bar);
Ответ 5
Существует определенный минимум, который может задержать на самом деле, и это сильно зависит от ОС, браузера, активности браузера и загрузки компьютера. Я, как правило, не опускаюсь ниже 20 мс, поскольку я думаю, что что-то меньшее, чем это, не имеет никакого значения.
Когда вы ставите две задержки, которые равны, это не обязательно означает, что это произойдет в этом порядке.
Если вы хотите, чтобы это было сделано, чтобы я сделал что-то вроде этого:
setTimeout(function() {
foo();
setTimeout(bar, 20)
}, 20);
Это всегда гарантирует порядок.
Если вы используете Firefox, чтобы убедиться, что ваш javascript на самом деле многопоточен, вы можете посмотреть на WebWorker, который поддерживается в новых браузерах, но не в IE.