I'm not quite grasping how exactly node works regarding async and loops. What I want to achieve here is have the console print out "Command: " and await for the user's input. But while it's waiting I want it to run "someRandomFunction()" endlessly until the user inputs "exit" onto the terminal.
Would appreciate all the help - and possibly an explanation so I can understand!
Thank you! :)
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question("Command: ", function(answer) {
if (answer == "exit"){
rl.close();
} else {
// If not "exit", How do I recall the function again?
}
});
someRandomFunction();
For NodeJS only – Use process. abort() or process. exit().
TL;DR: use break to exit a loop in JavaScript.
break terminates the execution of a for or while loop. Statements in the loop after the break statement do not execute. In nested loops, break exits only from the loop in which it occurs. Control passes to the statement that follows the end of that loop.
I would suggest making the function repeatable like so.
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
var waitForUserInput = function() {
rl.question("Command: ", function(answer) {
if (answer == "exit"){
rl.close();
} else {
waitForUserInput();
}
});
}
Then call
waitForUserInput();
someRandomFunction();
I'm unsure if the syntax you are using for .question is correct though, does that part of the code work?
You may also write this in the following manner.
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
function waitForUserInput() {
rl.question("Command: ", function(answer) {
if (answer == "exit"){
rl.close();
} else {
waitForUserInput();
}
});
}
The important lesson here is that to re-use a function it has to be named and be available in scope. If you have any more questions about this please ask.
The other answer is fine but uses recursion unnecessarily.
The key is to solving this is to separate, in your mind, the simple loop-based approach that is used in other languages from the asynchronous approach of Node.
In other languages, you might use a loop like this:
while not finished:
line = readline.read()
if line == 'woof':
print('BARK')
elif line == 'exit':
finished = True
... # etc
Node, at least with Readline, doesn't work this way.
In Node, you fire up Readline, give it event handlers, then return, and handle the completion of the readline loop later.
Consider this code, which you can copy-paste-run:
const readline = require('readline');
function replDemo() {
return new Promise(function(resolve, reject) {
let rl = readline.createInterface(process.stdin, process.stdout)
rl.setPrompt('ready> ')
rl.prompt();
rl.on('line', function(line) {
if (line === "exit" || line === "quit" || line == 'q') {
rl.close()
return // bail here, so rl.prompt() isn't called again
}
if (line === "help" || line === '?') {
console.log(`commands:\n woof\n exit|quit\n`)
} else if (line === "woof") {
console.log('BARK!')
} else if (line === "hello") {
console.log('Hi there')
} else {
console.log(`unknown command: "${line}"`)
}
rl.prompt()
}).on('close',function(){
console.log('bye')
resolve(42) // this is the final result of the function
});
})
}
async function run() {
try {
let replResult = await replDemo()
console.log('repl result:', replResult)
} catch(e) {
console.log('failed:', e)
}
}
run()
Run this and you'll get output like this:
$ node src/repl-demo.js
ready> hello
Hi there
ready> boo
unknown command: "boo"
ready> woof
BARK!
ready> exit
bye
repl result: 42
Note that the run
function calls replDemo
and "awaits" the result of the promise.
If you're unfamiliar with async/await, here's the same logic written it the "traditional" Promise style:
function run2() {
replDemo().then(result => {
console.log('repl result:', result)
}).catch(e => {
console.log('failed:', e)
})
console.log('replDemo has been called')
}
Note that I added output "replDemo has been called" for a reason - Running the above shows output like this:
$ node src/repl-demo.js
ready> replDemo has been called
woof
BARK!
ready> hello
Hi there
ready> bye
repl result: 42
Note how "replDemo has been called" appears immediately after the first "ready>" prompt. That's because the replDemo()
function returns immediately, then run2()
exits immediately, and the main
is all done - yet the readline is still executing!
That's hard to grasp if you come from an imperative programming background like me. The async event-driven loop at the core of nodejs keeps running until all the work is done, and that occurs when the last promise is resolved, which happens when the readline instance is "closed", which happens when "exit" is entered by the user (or EOF is received, which is CTRL+D on most systems, and CTRL+Z on Windows).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With