2016-09-01 2 views
1

У меня есть следующий кодПочему SetTimeout звонки сделать различный результат

setTimeout(function() { 
 
    setTimeout(function() { 
 
    console.log('foo'); 
 
    }, 50); 
 
}, 100); 
 

 
setTimeout(function() { 
 
    setTimeout(function() { 
 
    console.log('baz'); 
 
    }, 100); 
 
}, 50);

Вопрос заключался в том, что это выход. Но при запуске кода у меня разные результаты на нескольких тиражах - иногда это foo baz, иногда это baz foo.

Итак, есть два вопроса:

1) почему у меня есть разные результаты?

2) Почему иногда я получаю baz foo?

enter image description here

P.S. Есть фрагмент кода, но с фрагментом кода я всегда получаю тот же результат P.P.S. Если это специфическая среда - я использую Chrome (и FF), но вопросы по-прежнему актуальны P.P.S. Возможный ответ об использовании console.log, но

var a = []; 
 
setTimeout(function() { 
 
    setTimeout(function() { 
 
     a.push('foo'); 
 
     }, 50); 
 
}, 100); 
 
setTimeout(function() { 
 
    setTimeout(function() { 
 
     a.push('baz'); 
 
    }, 100); 
 
    }, 50); 
 
setTimeout(function() { console.log(a); }, 300);
это еще актуально

+2

его до среды javascript, чтобы правильно расположить объекты на бэкэнд. оба кажутся действительными ответами –

+2

setTimeout не назначает события после указанного времени EXACT - его приближение, которое используется механизмом javascript для планирования ваших функций как можно ближе к указанному вами времени. В общем, вы не должны полагаться на таймауты, чтобы гарантировать порядок исполнения. Читайте в очереди событий javascript для получения дополнительной информации. – matmo

+0

@SpencerWieczorek я имел в виду его реализацию. –

ответ

2

Указанный тайм-аут - это минимальное время ожидания браузера перед выполнением функции, а не гарантированное время. Если браузер занят другими вещами, когда таймер отключается, функция будет отложена.

Поэтому, когда вы планируете таймер на 50 мс, он может не работать до 53 мс позже. Затем после этого будет установлен еще один таймер на 100 мс, который после начала будет составлять 153 мс. Между тем таймер, установленный на 100 мс, может работать в 101 мс, а затем установить второй таймер на 50 мс позже, что составляет 151 мс после того, как все началось. В этом примере он напечатает foo bar.

Или вы можете получить разные задержки, и результатом будет bar foo.

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

+0

Я запускаю код на пустой странице. Что может сделать браузер рядом с моим кодом? –

+0

Сбор мусора, реагирование на движение мыши, другая внутренняя обработка. – Barmar

+0

пустая страница (новая вкладка), и я нахожусь в консоли - никакой мусор, никаких движений мыши. Я просто не могу помнить, что логика (. Thx для ответа –

2

SetTimeout не планировать вещи после EXACT вами время - его в качестве приближения, который используется в JavaScript двигателя планировать свои функции как можно ближе к указанному вами времени. В общем, вы не должны полагаться на таймауты, чтобы гарантировать порядок исполнения. Предположим, что ваш тайм-аут может занять некоторое время, и не ожидайте, что указанное время будет точным временем выполнения ваших функций.

Прочитано here для получения дополнительной информации.

+0

Это может объяснить, почему я получил 'baz foo'. Но не о разных результатах –

+0

Иногда функция с 'baz' запускается сначала, а иногда функция с' foo' запускается сначала - я не уверен, что вы имеете в виду. – matmo

+0

* «Важно отметить, что функция или фрагмент кода не могут быть выполнены до тех пор, пока поток, называемый setTimeout(), не будет завершен. Поскольку даже если setTimeout вызывается с задержкой в ​​0, он помещается в очередь и запускается на следующая возможность, а не сразу. В настоящее время исполняемый код должен завершиться до того, как выполняются функции в очереди, итоговый порядок выполнения ** может быть не таким, как ожидалось. »* – evolutionxbox

0

Добро пожаловать в мир асинхронного/управляемого событиями программирования!

Одним из ключевых моментов для понимания таймеров в javascript (и функций синхронизации общего назначения практически на всех языках) является то, что они не предназначены для точного определения tick. Вместо этого происходит то, что программа сообщает операционной системе/js engine «эй, отправьте мне уведомление, когда по крайней мере прошло столько времени.«Однако в операционной системе/js-движке могут быть сотни, тысячи или даже миллионы задач, необходимых для приоритизации и выполнения, поэтому он не может тратить все свое время, просто наблюдая, как часы ждут, чтобы скрыть это уведомление. , чтобы сохранить вычислительную мощность, сохраняет все эти события синхронизации в очереди и только периодически проверяет, сколько времени прошло, и если события истекли.

В вашем конкретном случае у вас есть событие тайм-аута, являющееся созданный в результате запуска события тайм-аута, поэтому, если начальное событие задерживается немного, это отталкивает время начала и, следовательно, истекает второе событие. В вашем примере foo/baz, если начальный тайм-аут foo задерживается, но начальный баз не является, тогда обратный вызов baz будет добавлен в очередь событий перед обратным вызовом foo, и вы получите «baz foo».

Или иногда baz будет задерживаться, а foo не будет, или иногда не будет, или иногда они оба будут. Слишком много происходит под капотом (возможно, даже не связано с вашим скриптом/кодом/программой), чтобы иметь возможность прогнозировать или полагаться на точный порядок выполнения. Это вынос, и это хорошая политика для жизни в основном для всех программ, управляемых событиями.

Смежные вопросы