0

I need to run multiple parallel tasks (infinite loops) without blocking each other in node.js. I'm trying now to do:

const test = async () => {
  let a = new Promise(async res => {
    while (true) {
      console.log('test1')
    }
  })

  let b = new Promise(async res => {
    while (true) {
      console.log('test2')
    }
  })
}

test();

But it does not work, only 'test1' appears in the console. What am I doing wrong?

Apoorva Chikara
  • 8,277
  • 3
  • 20
  • 35
Alexxosipov
  • 1,215
  • 4
  • 19
  • 45
  • You can't run even a single infinite loop in the main nodejs thread (unless there's an `await` in the loop) and have nodejs function properly. Nodejs relies on its event loop being able to run. An infinite loop starves the event loop. Perhaps you should describe your real problem and we could advise on a better way to solve the real problem because this is not the way to solve it. – jfriend00 Apr 14 '22 at 06:00
  • And, btw, wrapping synchronous code in an `async` function or in a promise does not help you in any way. Blocking synchronous code is still synchronous and blocking whether wrapped or not. – jfriend00 Apr 14 '22 at 06:03
  • I'm also curious why you think the code would ever advance past the first infinite `while` loop? It's an infinite loop. In your code structure, the 2nd loop doesn't get to execute until the first one is done. Neither promises or `async` callbacks change that in any way. – jfriend00 Apr 14 '22 at 06:06
  • FYI, there are worker threads in nodejs, but whether or not those are appropriate depends entirely upon what the actual, real problem is here. – jfriend00 Apr 14 '22 at 06:12
  • This is currently an [XY problem](https://en.wikipedia.org/wiki/XY_problem) where you've asked about a possible solution and not described the real problem at all. Since the solution you asked about is a dead-end (not the right way to go) and you haven't described the real problem, we can't help you with an good solution to your actual problem. Please try not to ask XY questions here as it just handicaps our ability to help you with the real problem. – jfriend00 Apr 14 '22 at 06:17
  • Nodejs is an event driven programming environment. Rather than infinite loops, you should be looking for an event driven solution to your problem. – jfriend00 Apr 14 '22 at 07:34

1 Answers1

3

You can't. You need to stop thinking in loops but start thinking in event loop instead.

There are two functions that can schedule functions to run in the future that can be used for this: setTimeout() and setInterval(). Note that in Node.js there is also setImmediate() but I suggest you avoid using it until you really know what you are doing because setImmediate() has to potential to block I/O.

Note that neither setTimeout() not setImmediate() are Promise aware.

The minimal code example that does what you want would be something like:

const test = () => {
  setInterval(() => {
      console.log('test1')
    },
    10 // execute the above code every 10ms
  )

  setInterval(() => {
      console.log('test2')
    },
    10 // execute the above code every 10ms
  )
}

test();

Or if you really want to run the two pieces of code as fast as possible you can pass 0 as the timeout. It won't run every 0ms but just as fast as the interpreter can. The minimal interval differs depending on OS and how busy your CPU is. For example Windows can run setInterval() down to every 1ms while Linux typically won't run any faster than 10ms. This is down to how fast the OS tick is (or jiffy in Linux terminology). Linux is a server oriented OS so sets its tick bigger to give it higher throughput (each process gets the CPU for longer thus can finish long tasks faster) while Windows is a UI oriented (some would say game oriented) OS so sets its tick smaller for smoother UI experience.

To get something closer to the style of code you want you can use a promisified setTimeout() and await it:

function delay (x) {
  return new Promise((done, fail) => setTimeout(done,x));
}

const test = async () => {
  let a = async (res) => {
    while (true) {
      console.log('test1')
      await delay(0) // this allows the function to be async
    }
  }

  let b = async (res) => {
    while (true) {
      console.log('test2')
      await delay(0) // this allows the function to be async
    }
  }

  a();
  b();
}

test();

However, this is no longer the minimal possible working code, though not by much.

Note: After writing the promisified example above it suddenly reminded me of the programming style on early cooperative multitasking OSes. I think Windows3.1 did this though I never wrote anything on it. It reminds me of MacOS Classic. You had to periodically call the WaitNextEvent() function to pass control of the CPU back to the OS so that the OS can run other programs. If you forgot to do that (or your program gets stuck in a long loop with no WaitNextEvent() call) your entire computer would freeze. This is exactly what you are experiencing with node where the entire javascript engine "freezes" and executes only one loop while ignoring other code.

slebetman
  • 109,858
  • 19
  • 140
  • 171