Используется ли setTimeout или setInterval для запуска потока?
Я читал эту статью http://ejohn.org/blog/how-javascript-timers-work/ и как setTimeout
и setInterval
и другие задачи async, такие как кнопка click confused me маленький.
Я знаю, что JS - это однопоточная, то есть AFAIK, все функции обратного вызова (обработчики событий a.k.a.) будут поставлены в очередь и выполняться в порядке. Однако посмотрите на изображение ниже, которое я взял из статьи, связанной выше:
![enter image description here]()
Каждый блок представляет некоторую работу, и - около 10 мс - таймер запускается. Я знаю, что его функция обратного вызова помещается в очередь для последующего выполнения, но как получилось, что событие может быть вызвано, пока что-то уже выполняется?
Это потому, что setTimeout()
начинает использовать отдельный поток, чтобы подсчитать время внутри и запустить его событие завершения?
Пожалуйста, обратите внимание, что я не говорю о его выполнении обратного вызова здесь; скорее, я пытаюсь понять, как setTimeout
может подсчитать время и завершить его завершение. Я знаю, что его обратный вызов будет вызван не раньше его заданных временных параметров, но может быть позже, но это связано с тем, что его обратный вызов поставлен в очередь до более позднего времени, когда среда выполнения находит какое-то время, чтобы проверить, есть ли что-нибудь для выполнения в очереди.
Как и в случае с этим вопросом, как браузеры допускают новый клик для регистрации, а - пусть говорят - цикл работает за кулисами в момент щелчка пользователя?
Если вы говорите, что браузеры поддерживают разные потоки для разных вещей, тогда мы можем называть JS в браузерах однопоточными?
Ответы
Ответ 1
JavaScript однопоточный, что означает, что два фрагмента JavaScript не будут выполняться одновременно (если не использовать worker, но каждый рабочий также является одиночным -threaded). Но JavaScript - это не единственная игра, когда дело доходит до API среды. Функции типа setTimeout
, setInterval
и addEventListener
реализованы изначально (или, по крайней мере, за пределами однопоточного JavaScript), и их обратные вызовы запускаются средой, например браузером. Это среда помещает эти обратные вызовы в очередь, которые должны выполняться одним поточным механизмом JavaScript. Именно так браузер может принимать новые события кликов, которые будут запущены, хотя он все еще выполняет какой-либо другой код JavaScript. Именно по этой причине JavaScript считается управляемым событиями.
Ответ 2
В настоящее время (Ecmascript 6) вам никогда не придется беспокоиться о том, что состояние меняется на полпути внутри функции.
Однако многие вещи действуют в фоновом режиме, и они меняют свою изолированную среду, которая позже потенциально отправляется в основную среду в виде фрагментов данных. Эта процедура обратного вызова XMLHttpRequest, таймеры и веб-рабочие все это делают. Все они потенциально работают одновременно (в нескольких процессорах), но все они взаимодействуют с основной средой последовательным образом.
Ответ 3
Нет необходимости иметь другие потоки, чтобы объяснить это поведение. Когда запись таймера добавляется в очередь, она просто сидит там. Если цикл события снова получает управление, он просто проверяет, есть ли запланированная задача, время которой вверх или нет.
Также нет необходимости в дополнительном потоке, чтобы сохранить глобальное время, поскольку оно уже доставлено операционной системой или средой выполнения.
Возьмем, к примеру, этот простой PhantomJS script:
function longRunningTask() {
for(var i = 0; i < 100000; i++) {
var s = "",
s2 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
for(var j = 0; j < 1000; j++) {
s += s2;
}
}
}
var start = new Date().getTime();
console.log("begin");
setTimeout(function(){
console.log("end timer 1s " + (new Date().getTime() - start));
}, 1000);
setTimeout(function(){
console.log("end timer 10s " + (new Date().getTime() - start));
}, 10000);
longRunningTask();
console.log("end longRunningTask " + (new Date().getTime() - start));
setTimeout(function(){
console.log("EXIT");
phantom.exit();
}, 11000);
Что производит следующий вывод:
begin
end longRunningTask 5025
end timer 1s 5029
end timer 10s 10001
EXIT
Один таймер запускается только тогда, когда элемент управления возвращается в цикл событий.