How does catching Ctrl-C works in Node?
Asked Answered
J

1

6

I have the following program in Node.js on Ubuntu:

process.on ("SIGINT", function(){
    console.log("You clicked Ctrl+C!");
    process.exit(1);
});

while(1) {

}

When I click Ctrl+C, I see "^C" on the screen, but nothing else is printed the process doesn't exit.

Without the "process.on..." statement, Ctrl+C immediately causes Node to exit.

What am I doing wrong?

Jeweljeweler answered 23/3, 2014 at 17:54 Comment(2)
I believe that since your while(1) loop is never yielding, the event loop isn't getting a turn to process the control-C. Otherwise, what you are doing looks like it should work.Hemocyte
Hmmm. I can try to answer this - how familiar are you with what signals are? Unlike in "C code" (aka, adding a signal handler with sigaction or signal directly) - in Node they don't cause the program to suddenly run other code. Instead, they are handled by node and "handed over" to the event loop. Since Node runs JavaScript single threaded (usually) and you never yield control - the event handler will never get called because the busy wait is deadlocking it (again, only one thing runs at a time). In Node you must never block the event loop.Lenis
P
4

As said above, the issue is that your while loop never yields and is blocking the event loop. If you need to make use of a while loop then making the loop part of an async function with at least 1 await call would resolve this issue:

const pause = () => new Promise(res => setTimeout(res, 0));

process.on ('SIGINT',() => {
  console.log('You clicked Ctrl+C!');
  process.exit(1);
});

(async function() {

  while(true) {
    console.log('Running Code');
    await pause();
  }
})();

Since async/await is syntactic sugar over Promises and not all environments support async/await, you could also do this directly with Promises if you are in a less modern environment, but the code would be much different:

const pause = () => new Promise(res => setTimeout(res, 0));

process.on ('SIGINT',() => {
  console.log('You clicked Ctrl+C!');
  process.exit(1);
});

const main = () => new Promise(() => {
  // do stuff
  console.log('Running Code');
});

function loop(task) {
  task();
  return pause().then(() => {
    task();
    return loop(task);
  });
}

loop(main);

Lastly, if you aren't using an environment with Promises there's also just replacing the while loop with an interval:

process.on ('SIGINT',() => {
  console.log('You clicked Ctrl+C!');
  process.exit(1);
});

setInterval(() => {
  console.log('Running Code');
}, 0)
Pedaias answered 11/1, 2018 at 12:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.