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

Как работает Javascript с одним потоком?

У меня вопрос о единственном потоковом характере Javascript.

console.log("1");
setTimeout(function(){console.log("2");},3000);
console.log("3");
setTimeout(function(){console.log("4");},1000);

Результат этого кода 1 3 4 2. Как вы видите, 4 появляется после 2, что заставляет задуматься, что в одной потоковой среде не должно 2 появилось после 4? Если нет, то почему JS знает, что второй setTimeout должен заканчиваться до первого? Не должно быть двух потоков, которые работают одновременно для завершения двух setTimeout, чтобы уведомить EventLoop?

4b9b3361

Ответ 1

JavaScript (в браузерах) не работает одновременно 2.

Не более одного обратного вызова setTimeout может выполняться одновременно - поскольку есть один контекст выполнения JavaScript или "поток".

Однако запуск следующего запланированного таймаута выполняется всегда. Далее. "4" работает до обратного вызова "2", потому что он должен был запускаться раньше. Таймауты были фактически запланированы с того же времени (ни одна из операций не блокировала), но "2" имели намного более длительный интервал.

В базовой реализации могут использоваться потоки 1 но JavaScript в том же глобальном контексте не работает одновременно и гарантирует согласованное и атомное поведение между всеми обратными вызовами.


1 Или это может быть не так; это можно обрабатывать без каких-либо потоков в реализации select/poll.

2 В том же контексте: например, Tab/Window, WebWorker, Host Browser Control. Например, хотя WebWorkers запускаются одновременно, они делают это в разных контекстах и ​​следуют одной и той же асинхронной модели (например, используемой таймерами).

Ответ 2

Javascript выполняет последовательность каждой строки.

Итак, вы сказали js:

  • напишите 1: js writes 1
  • подождите 3 секунды, а затем напишите 2: ok I'll wait 3 seconds...now what?
  • напишите 3: ok I'll write 3, by the way, the 3 seconds is not up.
  • подождите 1 секунду, а затем напишите 4: ok I'll wait 1 second...

то js ждет .99999 секунд... и пишет 4

затем ждет еще несколько и пишет 2

Ответ 3

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

Как только первый setTimeout встречается, функция выталкивается на место где-то снаружи, и ему предлагается ждать 3 секунды перед повторным входом в однопоточный мир. То же самое происходит для функции второго таймаута, но она должна ждать только 1 сек. Точкой входа в этот однопоточный мир является очередь обратного вызова. JS Engine продолжает нормальное выполнение, как если бы выполнение установки выполнялось с. Теперь, когда истекает 1 секунда, функция второго таймаута выталкивается в очередь и ожидает выполнения. Если в этот момент стек вызовов очищен, тогда функция переходит на обработку (при условии, что это был первый член очереди), и "4" печатается. Теперь, если 3 секунды не прошло за это время, функция первого таймаута все еще ждет где-то снаружи. Через 3 секунды функция обратного вызова входит в очередь, и, поскольку стек вызовов очищен, он выполняет и печатается "2".

Теперь браузер имеет доступ к нескольким потокам из ОС (хотя и предоставляет только одну поточную среду для выполнения JS). Эти setTimeouts обрабатываются другим потоком за сценой.

Существует видео от Philips Robert, которое прекрасно объясняет концепции цикла очереди и событий, которые приводят к "асинхронности" однопоточного javascript.

https://www.youtube.com/watch?v=8aGhZQkoFbQ

Ответ 4

Для асинхронных вызовов Javascript использует что-то, называемое Eventloop. SetTimeout переносится на EventLoop, поскольку это обратный вызов. и основной поток продолжает выполняться. Как только основное завершается, тогда EventLoop подталкивает данные к основному стеку. Пример:

console.log("1");
setTimeout(function(){console.log("2");},0);
console.log("3");
setTimeout(function(){console.log("4");},1000);

Когда таймаут равен 0, тогда вывод кода будет,

1 3 2 4

Поскольку он сначала выполняет вызовы Main, а затем возвращает данные из Eventloop Concurrency модель и цикл событий