Рассмотрим две приведенные ниже функции, обе асинхронные, одна из которых представляет собой жесткую рабочую нагрузку, занимающую много времени, а другая — функцию ожидания, которая ждет определенное количество секунд, устанавливая тайм-аут.
async function Brutal_Workload()
{
for(var x = 0; x< 1000 * 1000 * 1000; x++)
{
}
}
async function Time_Wait(seconds)
{
var promise = new Promise((resolve, reject) =>
{
var msecs = Math.floor(seconds * 1000);
var timer =
setTimeout(
function()
{
clearTimeout(timer);
resolve();
},
msecs);
});
return promise;
}
Теперь давайте вызовем первую функцию в цикле setInterval.
setInterval(
async function()
{
await Brutal_Workload();
console.info("BLIP");
}, 1000 / 30);
Все как положено: несмотря на то, что интервал составляет 30 вызовов в секунду, я получаю только 1 сигнал в секунду, потому что Brutal_Workload его душит.
Но когда я использую другую функцию...
setInterval(
async function()
{
await Time_Wait(1);
console.info("BLIP");
}, 1000 / 30);
Я получаю 30 BLIP в секунду. Функция Time_Wait, которая отлично работает за пределами setInterval, похоже, здесь не работает.
Любая идея о том, что может вызвать такое поведение?
А, верно, брутальная_ворклоад работает так, как вы и ожидали - извините... Я запутался :p
Ну, около 30 раз в секунду вызывается async function() { await Time_Wait(1); console.info("BLIP");} ... каждый вызов не зависит от предыдущего вызова, поэтому, конечно, вы получаете 30 сигналов в секунду (после начальной 1 секунды ничего)
Я не понимаю вопроса. Вы вызываете Timewait 30 раз в секунду, каждый ждет одну секунду, а затем регистрируется. Итак, после первой секунды вы увидите 30 в секунду. Это удивительно?
Оно ждет. Он ждет 1 секунду. Но после первой секунды последовательные вызовы будут складываться, и вы увидите 30 логов в секунду. @JaromandaX ты опередил меня на одну секунду :)
Верно, это как... что-то вроде каскада. Я пересек мои мозговые провода
@JaredSmith на самом деле, подождите секунду (без каламбура): если это происходит со второй функцией, то это должно произойти и с первой. Но это не так.
Каково ваше намерение сделать первую функцию асинхронной, а затем ожидать ее?
@MauricioRobayo нет особого намерения, я просто пытаюсь понять поведение, которое я наблюдал
«Если это происходит со второй функцией, это должно произойти и с первой. Но этого не происходит». Но это два разных зверя, в первом нет ничего асинхронного, даже если вы ожидаете его, ожидание не имеет никакого эффекта.
Ожидание @MauricioRobayo ожидает, в асинхронной функции выполнение не должно продолжаться до тех пор, пока обещание, возвращаемое другой асинхронной функцией, вызванной с помощью «ожидания», не будет разрешено.
Скрипты обновлены для ясности. СЛУЧАЙ 1: jsfiddle.net/9znv6g4a СЛУЧАЙ 2: jsfiddle.net/vu7fqpe1
Я имею в виду, что он по-прежнему блокируется, заставляя его ждать, это не меняет.
@MauricioRobayo Я знаю об этом. Дело в том, что если вы попробуете приведенную выше скрипку, вы увидите, что второй случай, который на самом деле должен блокироваться, как вы правильно утверждаете, НЕ блокируется.
Я никогда не говорил, что вторая функция блокируется, хотя. Не уверен, что это поможет stackoverflow.com/questions/42773714/… . Я до сих пор не уверен, почему вы ожидаете, что обе функции будут вести себя одинаково
Давайте продолжим обсуждение в чате.
Хорошо, вместо того, чтобы продолжать переписываться в комментариях, я просто опубликую это как ответ.
Javascript является одновременно однопоточным и параллельным. Я знаю, что вы это знаете, но вы, кажется, не понимаете последствий. В вашей первой функции вы только время от времени видите console.info, потому что ваша «жестокая рабочая нагрузка» блокирует единственный поток выполнения до его завершения, а это означает, что независимо от того, какой номер вы передали setInterval, не только не выполняется никакой другой вызов, следующая часть работы даже не ставится в очередь для запуска, потому что ваша жестокая рабочая нагрузка блокирует единственный поток выполнения.
Поймите, среда выполнения setInterval работает в том же (единственном) потоке, что и ваш код, движок JS не обманывает и не запускает ваши вещи в одном потоке, а setInterval в другом. Таким образом, в то время как жестокая нагрузка делает свое дело, setInterval сама по себе, не говоря уже о функции, которую вы ей передали, вообще не работает. Использование async и обертывание вашей жесткой рабочей нагрузки в Promise практически не имеет значения с точки зрения нашего обсуждения здесь, потому что преобладает жесткая рабочая нагрузка.
Так что это объясняет первый пример, пока все хорошо. На второй.
В отличие от первого примера, во втором нет длинного фрагмента кода, связывающего поток выполнения. Таким образом, ваш обратный вызов setInterval запускается, добросовестно регистрирует объект для запуска через секунду и дает контроль над потоком выполнения, чего опять же нет (и не может) в первом примере. Здесь Promise и async/await на самом деле обеспечивают параллелизм, который не может быть реализован в первом примере, потому что тяжелая рабочая нагрузка перегружает поток. Таким образом, через долю секунды ваш обратный вызов setInterval запускается снова, покорно ставит в очередь еще одну вещь для запуска по прошествии секунды и так далее.
Таким образом, через ~ 1 секунду происходит первый журнал в очереди, а затем через долю секунды после этого второй и так далее. Этого не происходит в первом примере, потому что, хотя вы сказали setInterval запустить брутальную рабочую нагрузку 30 раз в секунду, это означает, что setInterval сам не может запуститься даже для того, чтобы поставить ваш обратный вызов в очередь для запуска.
Спасибо за обширное объяснение. Понятно.
Я хорошо знаю об этом. Вы не поняли вопроса, прочтите еще раз