SetInterval/Async Await странность

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

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, похоже, здесь не работает.

Любая идея о том, что может вызвать такое поведение?

Я хорошо знаю об этом. Вы не поняли вопроса, прочтите еще раз

resle 20.11.2022 04:20

А, верно, брутальная_ворклоад работает так, как вы и ожидали - извините... Я запутался :p

Jaromanda X 20.11.2022 04:22

Ну, около 30 раз в секунду вызывается async function() { await Time_Wait(1); console.info("BLIP");} ... каждый вызов не зависит от предыдущего вызова, поэтому, конечно, вы получаете 30 сигналов в секунду (после начальной 1 секунды ничего)

Jaromanda X 20.11.2022 04:23

Я не понимаю вопроса. Вы вызываете Timewait 30 раз в секунду, каждый ждет одну секунду, а затем регистрируется. Итак, после первой секунды вы увидите 30 в секунду. Это удивительно?

Jared Smith 20.11.2022 04:24

Оно ждет. Он ждет 1 секунду. Но после первой секунды последовательные вызовы будут складываться, и вы увидите 30 логов в секунду. @JaromandaX ты опередил меня на одну секунду :)

Jared Smith 20.11.2022 04:25

Верно, это как... что-то вроде каскада. Я пересек мои мозговые провода

resle 20.11.2022 04:26

@JaredSmith на самом деле, подождите секунду (без каламбура): если это происходит со второй функцией, то это должно произойти и с первой. Но это не так.

resle 20.11.2022 04:40

Каково ваше намерение сделать первую функцию асинхронной, а затем ожидать ее?

MauricioRobayo 20.11.2022 04:50

@MauricioRobayo нет особого намерения, я просто пытаюсь понять поведение, которое я наблюдал

resle 20.11.2022 04:51

«Если это происходит со второй функцией, это должно произойти и с первой. Но этого не происходит». Но это два разных зверя, в первом нет ничего асинхронного, даже если вы ожидаете его, ожидание не имеет никакого эффекта.

MauricioRobayo 20.11.2022 04:56

Ожидание @MauricioRobayo ожидает, в асинхронной функции выполнение не должно продолжаться до тех пор, пока обещание, возвращаемое другой асинхронной функцией, вызванной с помощью «ожидания», не будет разрешено.

resle 20.11.2022 06:59

Скрипты обновлены для ясности. СЛУЧАЙ 1: jsfiddle.net/9znv6g4a СЛУЧАЙ 2: jsfiddle.net/vu7fqpe1

resle 20.11.2022 07:07

Я имею в виду, что он по-прежнему блокируется, заставляя его ждать, это не меняет.

MauricioRobayo 20.11.2022 11:04

@MauricioRobayo Я знаю об этом. Дело в том, что если вы попробуете приведенную выше скрипку, вы увидите, что второй случай, который на самом деле должен блокироваться, как вы правильно утверждаете, НЕ блокируется.

resle 20.11.2022 11:30

Я никогда не говорил, что вторая функция блокируется, хотя. Не уверен, что это поможет stackoverflow.com/questions/42773714/… . Я до сих пор не уверен, почему вы ожидаете, что обе функции будут вести себя одинаково

MauricioRobayo 20.11.2022 11:59

Давайте продолжим обсуждение в чате.

resle 20.11.2022 12:12
Как использовать API парсинга квитанций с помощью JavaScript за 5 минут?
Как использовать API парсинга квитанций с помощью JavaScript за 5 минут?
В этом руководстве вы узнаете, как использовать API парсинга квитанций за 5 минут с помощью JavaScript. Eden AI предоставляет простой и удобный для...
Хук useOnClickOutside в ReactJS
Хук useOnClickOutside в ReactJS
Как разработчик ReactJS, вы, возможно, сталкивались с ситуацией, когда вам нужно закрыть модальное или выпадающее меню, когда кто-то щелкает за его...
Хуки (часть-2) - useEffect
Хуки (часть-2) - useEffect
Хук useEffect - один из самых мощных и универсальных инструментов в арсенале разработчика React. Он позволяет вам управлять побочными эффектами в...
Простое руководство по тестированию взаимодействия с пользователем с помощью библиотеки тестирования React
Простое руководство по тестированию взаимодействия с пользователем с помощью библиотеки тестирования React
В предыдущем посте я показал вам на примерах, как писать базовые тесты в React. Важнейшей частью пользовательского интерфейса приложений является...
Как конвертировать HTML в PDF с помощью jsPDF
Как конвертировать HTML в PDF с помощью jsPDF
В этой статье мы рассмотрим, как конвертировать HTML в PDF с помощью jsPDF. Здесь мы узнаем, как конвертировать HTML в PDF с помощью javascript.
Создайте титры как в звездных войнах с помощью CSS и Javascript
Создайте титры как в звездных войнах с помощью CSS и Javascript
Если вы веб-разработчик (или хотите им стать), то вы наверняка гик и вам нравятся "Звездные войны". А как бы вы хотели, чтобы фоном для вашего...
0
16
70
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Хорошо, вместо того, чтобы продолжать переписываться в комментариях, я просто опубликую это как ответ.

Javascript является одновременно однопоточным и параллельным. Я знаю, что вы это знаете, но вы, кажется, не понимаете последствий. В вашей первой функции вы только время от времени видите console.info, потому что ваша «жестокая рабочая нагрузка» блокирует единственный поток выполнения до его завершения, а это означает, что независимо от того, какой номер вы передали setInterval, не только не выполняется никакой другой вызов, следующая часть работы даже не ставится в очередь для запуска, потому что ваша жестокая рабочая нагрузка блокирует единственный поток выполнения.

Поймите, среда выполнения setInterval работает в том же (единственном) потоке, что и ваш код, движок JS не обманывает и не запускает ваши вещи в одном потоке, а setInterval в другом. Таким образом, в то время как жестокая нагрузка делает свое дело, setInterval сама по себе, не говоря уже о функции, которую вы ей передали, вообще не работает. Использование async и обертывание вашей жесткой рабочей нагрузки в Promise практически не имеет значения с точки зрения нашего обсуждения здесь, потому что преобладает жесткая рабочая нагрузка.

Так что это объясняет первый пример, пока все хорошо. На второй.

В отличие от первого примера, во втором нет длинного фрагмента кода, связывающего поток выполнения. Таким образом, ваш обратный вызов setInterval запускается, добросовестно регистрирует объект для запуска через секунду и дает контроль над потоком выполнения, чего опять же нет (и не может) в первом примере. Здесь Promise и async/await на самом деле обеспечивают параллелизм, который не может быть реализован в первом примере, потому что тяжелая рабочая нагрузка перегружает поток. Таким образом, через долю секунды ваш обратный вызов setInterval запускается снова, покорно ставит в очередь еще одну вещь для запуска по прошествии секунды и так далее.

Таким образом, через ~ 1 секунду происходит первый журнал в очереди, а затем через долю секунды после этого второй и так далее. Этого не происходит в первом примере, потому что, хотя вы сказали setInterval запустить брутальную рабочую нагрузку 30 раз в секунду, это означает, что setInterval сам не может запуститься даже для того, чтобы поставить ваш обратный вызов в очередь для запуска.

Спасибо за обширное объяснение. Понятно.

resle 20.11.2022 14:21

Другие вопросы по теме