2

I am trying to implement a simple yes/no script.

A function runs, then the user is prompt to input whether or not to run it again.

If the user inputs "y", then the procedure should repeat.

If the user inputs "n", then the procedure should terminate.

If neither, then the question should repeat.

Here is my code:

function func(i) {
    console.log(i);
    ask(i + 1);
}

function ask(i) {
    process.stdout.write("again (y/n)?");
    process.stdin.on("data", function(data) {
        process.stdin.end();
        if (data.toString().trim() == "y")
            func(i);
        else if (data.toString().trim() != "n")
            ask(i);
    });
}

func(0);

Unfortunately, the process always terminates at the second time the question is asked.

I tried removing the process.stdin.end() part, and I got a really weird behavior:

First time I input "y", the question is asked once and the function runs once.

Second time I input "y", the question is asked twice and the function runs twice.

Third time I input "y", the question is asked thrice and the function runs thrice.

In addition, at some point I start getting this error:

(node:12336) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 data listeners added. Use emitter.setMaxListeners() to increase limit

What might be going on here?

halfer
  • 19,824
  • 17
  • 99
  • 186
goodvibration
  • 5,980
  • 4
  • 28
  • 61

1 Answers1

3

The line

process.stdin.end();

prevents further input, and (here) effectively ends the program. So, you'll want to call it only once, once everything is done. The

process.stdin.on

command adds a listener to when the user presses "enter". If you call this multiple times, multiple listeners will be added.

So, you might consider adding just one listener, calling process.stdin.end(); if the response is n:

let i = 0;
function func() {
  console.log(i);
  i++;
  ask();
}
process.stdin.on("data", function(data) {
  if (data.toString().trim() === "y")
    func(i);
  else if (data.toString().trim() === "n")
    process.stdin.end();
  else
    ask();
});
function ask() {
  process.stdout.write("again (y/n)?");
}

func();

Output example:

PS D:\Downloads> node foo.js
0
again (y/n)?
again (y/n)?
again (y/n)?y
1
again (y/n)?y
2
again (y/n)?
again (y/n)?y
3
again (y/n)?n
PS D:\Downloads>
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • This is an amazing piece of work. Thank you very much for the effort in writing this precise answer!!! – goodvibration Jan 06 '19 at 08:23
  • I do have a certain problem though. If you insist, then I can ask it in a separate question, but my purpose was to block the execution until the user has entered either 'y' or 'n'. Here, however, execution continues without waiting for user-input. For example, try to add a printout immediately after the last line (where you call `func`), and you'll see that it executes. How can I resolve this? I tried polling on a variable changed inside the `process.stdin.on` callback, but it blocked the entire thread (which makes sense if you think about it). Any idea how to resolve this? – goodvibration Jan 06 '19 at 10:44
  • You're asking about something somewhat similar to https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call . Not sure what sort of logic you're looking for exactly, but extra functionality that depends on the result of the input data should go in the `if` / `else if` blocks of the `stdin.out` listener. eg `if (...) { func(); doSomethingElse(); }` – CertainPerformance Jan 06 '19 at 10:52
  • If you can describe the output you're looking for, it should be simple to tweak the code above – CertainPerformance Jan 06 '19 at 10:54
  • `process.stdin.out is not a function` – goodvibration Jan 06 '19 at 10:55
  • I can describe it, but I guess I'll need to post a separate question for that. – goodvibration Jan 06 '19 at 10:56
  • Posted at https://stackoverflow.com/q/54060882/7400903. Thank you for your help :) – goodvibration Jan 06 '19 at 11:05