-1

I'm running the following bit of code to get input from the terminal in nodejs (I picked this method because it doesn't need dependencies) and I need it to work synchronously. It's inside a function that gets called repeatedly by a for loop and thus in its current async state it's causing some problems.

Here's the function that i'd like to make synchronous:

standard_input.on('data', function (data) {
 choice = data;
 if (choice == 1) response = rp.r1;
if (choice == 2) response = rp.r2;


console.log("[" + character.name + "]: " + response);
});

Thanks for your help!

EDIT: More detailed explanation of my situation and code as follows:

I have a for loop that calls a synchronous function, conversation(). In this function there is a section of code which requires that the for loop halt until the user has input something. I'm asking for a way to do that either with my existing method of getting user input (shown above) or a different one.

EDIT 2: THE SEQUEL:

More complete snippet of my code to help with answers, as some of the provided answers don't work for me because I wasn't clear enough about what I'm trying to do.

function conversation(character, num, rp) {
if (negStreak >= 4) {
  return false;
}
var choice;
var response;

console.log("CHOICES:");
console.log("(1): " + rp.c1);
console.log("(2): " + rp.c2);
console.log("Type 1 or 2 and hit Enter.");

standard_input.on('data', function (data) { //this is how i'm getting input
 choice = data;
 if (choice == 1) response = rp.r1;
if (choice == 2) response = rp.r2;
negStreak++

console.log("[" + character.name + "]: " + response);
});

}

function game(char) {
  negStreak = 0;
if (char.name == "Vern") array = vern_conv;
if (char.name == "Jericho") array = jericho_conv;
if (char.name == "Las") array = las_conv;
if (char.name == "char3") array = char3_conv;
if (char.name == "char4") array = char4_conv;

for (i = 0; i < array.length; i++) { //this is the for loop i'm talking about
var reactionPair = array[i];
conversation(char, i, reactionPair);
}
}
  • 4
    You cannot make an event driven thing be synchronous in Javascript. It is by its very definition, event-driven, not synchronous. If you show the larger problem that you're trying to solve and code that goes with it, we can show you ways to solve that. FYI, as stated, this is an [XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) where you're asking about one particular solution rather than showing us what the original problem is. In your specific case, you're also asking about the wrong solution direction. – jfriend00 Jun 16 '20 at 00:01
  • Could you clarify why the function has to be synchronous as you are triggering it(Dom events are asyncronous)? Cant you just get the code inside the function and move to a regular function and call that synchronously and also asyncronously from this event handler? – dabishan Jun 16 '20 at 00:01
  • 1
    regarding halting in a for loop, you could try generator functions – George Jun 16 '20 at 00:12
  • @George care to elaborate? – TheDeveloperNextDoor Jun 16 '20 at 00:14
  • Please show the ACTUAL code for the `for` loop so we can see what you're really trying to do. The whole concept of adding a new event handler every time you go through the `for` loop is always wrong as they will just pile up with lots of duplicate event handlers. – jfriend00 Jun 16 '20 at 00:46

2 Answers2

0

if understood what you need correctly you will need to use async and await to wait for the data to be assigned in your function so you may want to try something like this

    async function userinput(){
   return await new Promise(resolve=>{
    standard_input.on('data', function passdata (data) {
      standard_input.removeEventListener("data",passdata);

      choice = data;
      if (choice == 1) resolve(response = rp.r1);
     if (choice == 2) resolve(response = rp.r2)
     console.log("[" + character.name + "]: " + response);
     });
  })
}
userinput()
Sven.hig
  • 4,449
  • 2
  • 8
  • 18
  • 1
    It is highly unlikelly that `standard_input.on('data',...)` returns a promise, therefore using `await` on it does nothing. – jfriend00 Jun 16 '20 at 00:45
  • @jfriend00 I know this may sound like a stretch but if the `standard_input.on` is used inside a promise and then return the promise will that work ? – Sven.hig Jun 16 '20 at 00:56
  • 1
    No, that won't work either. One would have to promisify the event handler (manually wrapping it in a promise and would have to remove the event handler after the event fired). Events are a bad match for promises like this because promises are one shot devices and events like this one are multi-shot devices. – jfriend00 Jun 16 '20 at 01:03
  • Thank you for your response, I have just updated my code will something like that work for events is that what you meant ?, I am trying to understand the possibility of using events with promises, and thank you for your time – Sven.hig Jun 16 '20 at 01:23
0

Instead of wrapping your input in a for loop...

for (loop var) {
  input = prompt_for_input <--- oh no, this is inherently async
  do something with input
}

make your loop iterate as a result of input, so it looks like this...

prompt_for_input
whenWeGetInput(
  do something with input
  prompt_for_input // <-- this is your loop now
) 

nodejs readline allows for this kind of loop using createInterface...

const readline = require('readline')
let rl = readline.createInterface(process.stdin, process.stdout)

rl.setPrompt('$ ')
rl.prompt()

rl.on('line', choice => {
  switch(choice.trim()) {
    case '1':
      console.log('you typed 1')
      break
    case '2':
      // and so on
    default:
      console.log(`you typed something else: ${choice}`)
      break
    }
    rl.prompt() // <-- this is your loop now
}).on('close', () => {
  process.exit(0)
})
danh
  • 62,181
  • 10
  • 95
  • 136