Почему setTimeout не отменяет мой цикл?
Я задавался вопросом, сколько раз инструкция JavaScript while
(в консоли Chrome) может увеличивать переменную за миллисекунду, поэтому я быстро написал этот фрагмент непосредственно в консоль:
var run = true, i = 0;
setTimeout(function(){ run = false; }, 1);
while(run){ i++; }
Проблема в том, что она работает вечно.
Почему это происходит, и как я могу его решить?
Ответы
Ответ 1
Это возвращается к однопоточному характеру JavaScript 1. Что происходит в значительной степени:
- Ваши переменные назначены.
- Вы планируете функцию, чтобы установить
run = false
. Это запланировано для запуска после текущей функции (или что-то еще в настоящее время активно).
- У вас есть бесконечный цикл и оставайтесь внутри текущей функции.
- После бесконечного цикла (никогда) будет выполнен обратный вызов
setTimeout()
и run=false
.
Как вы можете видеть, подход setTimeout()
не работает здесь. Вы можете обойти это, проверив время в while
, но это повлияет на ваше фактическое измерение.
1 По крайней мере, для более практических целей вы можете видеть это как однопоточное. На самом деле существует так называемый "цикл событий". В этом цикле все функции попадают в очередь до их выполнения. Если вы ставите в очередь новую функцию, она помещается в соответствующую позицию внутри этой очереди. После того, как текущая функция завершена, движок выполняет следующую функцию из очереди (относительно введенных значений времени, например, setTimeout()
и выполняет ее.
В результате в каждый момент времени выполняется только одна функция, что делает выполнение в значительной степени однопоточным. Существуют некоторые исключения для событий, которые обсуждаются в приведенной ниже ссылке.
Для справки:
Ответ 2
JavaScript является однопоточным, поэтому, пока вы находитесь в цикле, ничего не запускается.
Ответ 3
Чтобы сохранить истинную скорость работы Chrome без необходимости постоянно получать время для вычисления скорости, вы можете попробовать этот код JS:
var start = new Date().getTime()
var i = 0
while(i<1000000)
{
i++
}
var end = new Date().getTime()
var delta = end-start
var speed = i/delta
console.log(speed + " loops per millisecond")
Ответ 4
Javascript является однопоточным, что означает, что он запускает только одну команду за раз, последовательно.
Система событий, как и во многих других языках и в библиотеке, является обработкой циклом события. Цикл событий в основном представляет собой цикл, который на каждой итерации проверяет сообщение в очереди и передает события.
В javascript (как в языке языков, реализующих этот шаблон) цикл события вызывается, когда стек пуст, то есть когда все функции возвращаются, другими словами, в конце программного кода.
Ваша "настоящая" программа выглядит примерно так:
var run = true, i = 0;
setTimeout(function(){ run = false; }, 1);
while(run){ i++; }
while(true) {
/*
* check for new messages in the queue and dispatch
* events if there are some
*/
processEvents();
}
Таким образом, сообщение с тайм-аутом, указывающим часы, никогда не обрабатывается.
Дополнительная информация о цикле событий:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/EventLoop
Конечно, это немного сложнее, проверьте здесь эти примеры: Является ли JavaScript гарантированным однопоточным? ( tl; dr: В некоторых браузерах некоторые внешние события не зависят от цикла событий и сразу же запускаются, когда они возникают, вытесняя текущую задачу. Но это не относится к setTimeout, которые просто добавляют сообщение в очередь и никогда не срабатывают немедленно.)
Ответ 5
Цикл While не имеет доступа к setTimeout. У вас есть код, который устанавливает run true, а затем он никогда не станет false.
Ответ 6
JavaScript имеет один поток и имеет однопоточность в любом месте.
Я думаю, что этот вопрос в порядке:
Является ли JavaScript гарантированным однопоточным?
Когда ваш код находится в цикле, другие ocde не выполняются и блокируются.