JoshJ JoshJ - 1 year ago 138
Node.js Question

Block for stdin in Node.js

Short explanation:

I'm attempting to write a simple game in

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
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
how would I go about doing it and still follow best practices?

Answer Source

I agree with the comment about moving towards an event based system and would ditch the loops. I've thrown together a quick example of text based processing which can be used for simple text games.

var fs = require('fs'),
    es = require('event-stream');

    .on('data', parseCommand);

var actionHandlers = {};

function parseCommand(command) {
    var words = command.split(' '),
        action = '';

    if(words.length > 1) {
        action = words.shift();

    if(actionHandlers[action]) {
    } else {

function invalidAction(action) {
    console.log('Unknown Action:', action);

actionHandlers['move'] = function(words) {
    console.log('You move', words);

actionHandlers['attack'] = function(words) {
    console.log('You attack', words);

You can now break up your actions into discrete functions which you can register with a central actionHandlers variable. This makes adding new commands almost trivial. If you can add some details on why the above approach wouldn't work well for you, let me know and I'll revise the answer.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download