Search code examples
node.jsstdinblocking

Block for stdin in Node.js


Short explanation:

I'm attempting to write a simple game in Node.js that needs to wait for user input every turn. How do I avoid callback hell (e.g. messy code) internal to a turn loop where each turn loop iteration needs to block and wait for input from stdin?

Long explanation:

All the explanations I have read on StackOverflow when someone asks about blocking for stdin input seem to be "that's not what Node.js is about!"

I understand that Node.js is designed to be non-blocking and I also understand why. However I feel that it has me stuck between a rock and a hard place on how to solve this. I feel like I have three options:

  1. Find a way to block for stdin and retain my while loop
  2. Ditch the while loop and instead recursively call a method (like nextTurn) whenever the previous turn ends.
  3. Ditch the while loop and instead use setTimeout(0, ...) or something similar to call a method (like nextTurn) whenever a turn ends.

With option (1) I am going against Node.js principles of non-blocking IO. With option (2) I will eventually reach a stack overflow as each call adds another turn to the call stack. With option (3) my code ends up being a mess to follow.

Internal to Node.js there are default functions that are marked **Sync (e.g. see the fs library or the sleep function) and I'm wondering why there is no Sync method for getting user input? And if I were to write something similar to fs.readSync how would I go about doing it and still follow best practices?


Solution

  • Just found this: https://www.npmjs.com/package/readline-sync

    Example code (after doing an npm install readline-sync)

    var readlineSync = require('readline-sync');
    while(true) {
      var yn = readlineSync.question("Do you like having tools that let you code how you want, rather than how their authors wanted?");
      if(yn === 'y') {
        console.log("Hooray!");
      } else {
        console.log("Back to callback world, I guess...");
        process.exit();
      }
    }
    

    Only problem so far is the wailing of the "That's not how node is meant to be used!" chorus, but I have earplugs :)