0

Consider the two functions below, both async, one a brutal workload that takes a lot of time, and the other one a wait function that waits a precise number of seconds by setting a timeout.

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;
}

Now, let's call the first function in a setInterval cycle

setInterval(
async function()
{
 await Brutal_Workload();
    
 console.log("BLIP");
}, 1000 / 30);

All as intended: despite the interval running at 30 calls per second, I only get 1 blip per second, because Brutal_Workload is choking it.

But when I use the other function...

setInterval(
async function()
{
 await Time_Wait(1);
    
 console.log("BLIP");
}, 1000 / 30);

I get 30 BLIPs per second. The Time_Wait function, which works otherwise just fine outside of setInterval, doesn't seem to work here.

Any idea of what might cause this behavior?

resle
  • 2,254
  • 4
  • 19
  • 37
  • I am well aware of that. You did not understand the question, please read again – resle Nov 20 '22 at 03:20
  • Oh, right, the brutal_workload works as you expected - sorry ... I was confused :p – Jaromanda X Nov 20 '22 at 03:22
  • Well, about 30 times a second `async function() { await Time_Wait(1); console.log("BLIP");}` is called ... each call is independent of the previous call, so of course you get 30 blips a second (after an initial 1 second of nothing) – Jaromanda X Nov 20 '22 at 03:23
  • 1
    I don't understand the question. You call the Timewait 30 times per second, each waits one second then logs. So after the first second you'll see 30 per second. Is that surprising? – Jared Smith Nov 20 '22 at 03:24
  • 1
    It *does* wait. It waits for 1 second. But after the first second the successive calls will be stacked up, and you'll see 30 logs per second. @JaromandaX you beat me by one second :) – Jared Smith Nov 20 '22 at 03:25
  • 1
    Right, it's like... a cascade kind of thing. I got my brain wires crossed – resle Nov 20 '22 at 03:26
  • @JaredSmith actually, wait a second (no pun intended): if it happens with the 2nd function, it should happen with the first as well. But it doesn't. – resle Nov 20 '22 at 03:40
  • What's your intention by making the first function async and then awaiting on it? – MauricioRobayo Nov 20 '22 at 03:50
  • @MauricioRobayo there is no specific intention, I am just trying to understand a behavior I have observed – resle Nov 20 '22 at 03:51
  • 1
    "if it happens with the 2nd function, it should happen with the first as well. But it doesn't." But those are two different beasts, there is nothing asynchronous going on in the first one, even if you await on it, awaiting on it has no effect. – MauricioRobayo Nov 20 '22 at 03:56
  • @MauricioRobayo awaiting is awaiting, in an async function execution is not supposed to continue until the promise returned by the other async function called with "await" is resolved. – resle Nov 20 '22 at 05:59
  • Fiddles updated for clarity CASE 1: https://jsfiddle.net/9znv6g4a/ CASE 2 : https://jsfiddle.net/vu7fqpe1/ – resle Nov 20 '22 at 06:07
  • I mean, It is still blocking making it await does not change that. – MauricioRobayo Nov 20 '22 at 10:04
  • @MauricioRobayo I am aware of that. The point is, if you try the above fiddle, you will see that 2nd case, which is in fact supposed to be blocking - as you correctly state - is NOT blocking. – resle Nov 20 '22 at 10:30
  • I never said the second function was blocking, tho. Not sure if this can help https://stackoverflow.com/questions/42773714/is-async-await-truly-non-blocking-in-the-browser . I'm still not sure why would you expect both functions to behave the same – MauricioRobayo Nov 20 '22 at 10:59
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/249750/discussion-between-resle-and-mauriciorobayo). – resle Nov 20 '22 at 11:12

1 Answers1

3

Ok, rather than continue the back-and-forth in the comments, I'm just going to post this as an answer.

Javascript is both single-threaded and concurrent. I know you know this, but you don't seem to realize the implications. In your first function, you only see a console.log every so often, because your "brutal workload" blocks the only thread of execution until it completes, which means that regardless of what number you passed to setInterval not only is no other invocation running, the next bit of work isn't even being queued to run because your brutal workload is blocking the only thread of execution.

Understand, the runtime environment's setInterval runs on the same (only) thread as your code, the JS engine doesn't cheat and run your stuff in one thread and setInterval in another. So while brutal workload is doing its thing, setInterval itself, much less the function you passed to it, is not running at all. Using async and wrapping your brutal workload in a Promise makes essentially zero difference in terms of our discussion here, because brutal workload dominates.

So that explains the first example, so far so good. On to the second.

Unlike the first example, in the second there is no long-running chunk of code to tie up the thread of execution. So your callback to setInterval runs, dutifully registers a thing to run in a second, and yields control of the thread of execution, something that again the first example does not (and cannot do). Here the Promise and async/await actually does enable concurrency which it can't do in the first example because brutal workload is hogging the thread. So in a fraction of a second your callback to setInterval runs again, dutifully queues up another thing to run after a second has passed, and so on.

So after ~1 second that first queued up log happens, and then after a fraction of a second after that the second, and then so on. This doesn't happen in the first example because although you told setInterval to run 30x/sec brutal workload means that setInterval itself can't run to even queue your callback to be ran.

Jared Smith
  • 19,721
  • 5
  • 45
  • 83