Подтвердить что ты не робот

Порядок выполнения нескольких функций setTimeout() с одинаковым интервалом

Рассмотрим следующий код Javascript:

function(){
    setTimeout(function() {
        $("#output").append(" one ");
    }, 1000);
    setTimeout(function() {
        $("#output").append(" two ");
    }, 1000);
}

Вы также можете увидеть этот пример на jsfiddle.

Могу ли я быть уверенным, что значение #output всегда "one two", в этом порядке? Обычно я бы справился с этой проблемой следующим образом:

function(){
    setTimeout(function() {
        $("#output").append(" one ");
        $("#output").append(" two ");
    }, 1000));
}

Но я не могу так поступать, потому что получаю сообщения с сервера, который сообщает мне, какую функцию выполнять (в этом примере добавить "one" или append "two"), который я должен выполнить с небольшой задержкой.

Я уже тестировал этот код в Internet Explorer 9, Firefox 14, Chrome 20 и Opera 12, а вывод всегда был "one two", но могу ли я быть уверенным, что это всегда будет?

4b9b3361

Ответ 1

Спецификация здесь.

Моя интерпретация шага 8 setTimeout в разделе 7.3 заключается в том, что предполагается выполнение порядка выполнения.

Однако я исследовал эту проблему, потому что, когда окно минимизировано и затем максимизировано в Chrome, я обнаружил, что таймауты, установленные в событиях, поступающих из внешних источников (например, веб-узлов или веб-мастеров), выполнялись в неправильном порядке. Я предполагаю, что это ошибка браузера и, надеюсь, скоро будет исправлена.

Ответ 2

Играйте с этим в своей скрипке

$(document).ready(function() {
    setTimeout(function() {
        $("#output").append(" one ");
    }, 1000);
});
$(document).ready(function() {
    setTimeout(function() {
        $("#output").append(" two ");
    }, 999);
});​

И вы увидите, что оба

output: one two
output: two one

возможны. Так что Сперанский прав, что вы не можете всегда полагаться на свои тайм-ауты в том же порядке.

Обратите внимание, что я меняю один раз на 1 мс, чтобы показать, что тайм-аут 1000 мс может выполняться до истечения 999 мс.

EDIT: приведенный ниже код может задержать выполнение без возможности two напечатать перед one

function(){
    setTimeout(function() {
        $("#output").append(" one ");
       setTimeout(function() {
           $("#output").append(" two ");
       }, 100);
    }, 1000);
}

Ответ 3

Да, поскольку код javascript выполняется в одном потоке, все асинхронные события, такие как click, mousemove, помещаются в очередь для выполнения. Когда вы вызываете setTimeout, двигатель вставляет таймер в свою очередь для выполнения в будущем, по крайней мере, после delay времени. Таким образом, два setTimeout генерируют два таймера один за другим.

Вы можете посмотреть Как работает Javascript Timers от Джона Ресига.

Ответ 4

Нет, вы не можете быть уверены. Это асинхронно.

Но на самом деле это, вероятно, будет верно, из-за реализации механизма в браузерах.

Ответ 5

Да, выход всегда будет "one two".

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

Ответ 6

Обновление
Я обновил вашу скрипку с помощью этого метода. Проверьте здесь

Как насчет этого метода - Получите список вещей, которые нужно сделать с вашего сервера -

//Example - append one, append two
var appendList = ['one', 'two']

//then do this
appendList.forEach(function(item, index){
    setTimeout(function(){ 
        $('#output').append(item)
    }, index * 50 + 1000);
});

Таким образом, вы определяете последовательность.

Ответ 7

Если события синхронны, существует функция Continuum для запуска функций последовательно:

function keyedSequence(key, fn) {
  fn = fn || this;
  key.push({fn:fn});

  return function() {
    for(var i=0, n, full=1; i<key.length; i++) {
      n = key[i];
      if(n.fn == fn) {
        if(!n.called) n.called = 1, n.args = key.slice.call(arguments);
        if(!full) break
      }
      if(!n.called) full = 0
    }

    if(full) for(i=0; i<key.length; i++)
      n = key[i], key[i] = {fn:n.fn}, n.fn.apply(n, n.args);
  }
}
Function.prototype.seq = keyedSequence;

Вы предоставляете пустой массив в качестве ключа. Функции, связанные с одним и тем же ключом, будут сгруппированы вместе.

window.onload = function() {
  var key = [];
  document.getElementById("test1").addEventListener('click', function1.seq(key), false);
  document.getElementById("test2").addEventListener('click', function2.seq(key), false);
}

Нажмите test2, затем нажмите test1, а порядок выполнения все еще function1, затем function2.

Другой способ вызова:

window.onload = function() {
  var key = [];
  document.getElementById("test1").addEventListener('click', keyedSequence(key, function1), false);
  document.getElementById("test2").addEventListener('click', keyedSequence(key, function2), false);
}