简短说明:
我试图在Node.js
中编写一个需要等待用户输入的简单游戏。我如何在转弯循环内部avoid callback
地狱(例如凌乱的代码),每个转弯循环迭代需要阻止并等待来自标准输入的输入?
长解释:
当有人要求阻止stdin
输入时,我在StackOverflow上读到的所有解释似乎都是"那不是Node.js的意思!"
我知道Node.js设计为非阻塞,我也理解为什么。但是我觉得它让我陷入困境和如何解决这个问题的困难之中。我觉得我有三个选择:
使用选项(1)我将反对Node.js非阻塞IO的原则。 使用选项(2),我将最终达到堆栈溢出,因为每次调用都会向调用堆栈添加另一个转弯。 使用选项(3),我的代码最终会变得一团糟。
Node.js内部有默认功能,标记为** Sync(例如,参见fs库或睡眠功能),我想知道为什么没有用于获取用户输入的Sync方法?如果我要写一些与fs.readSync
类似的东西,我将如何去做并仍然遵循最佳实践?
答案 0 :(得分:11)
刚刚发现: https://www.npmjs.com/package/readline-sync
示例代码(执行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();
}
}
到目前为止,唯一的问题是"这不是节点的意图如何使用!"合唱,但我有耳塞:)
答案 1 :(得分:2)
我同意关于转向基于事件的系统的评论,并且会放弃循环。我将基于文本的处理的快速示例放在一起,可以用于简单的文本游戏。
var fs = require('fs'),
es = require('event-stream');
process.stdin
.pipe(es.split())
.on('data', parseCommand);
var actionHandlers = {};
function parseCommand(command) {
var words = command.split(' '),
action = '';
if(words.length > 1) {
action = words.shift();
}
if(actionHandlers[action]) {
actionHandlers[action](words);
} else {
invalidAction(action);
}
}
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);
}
现在,您可以将操作分解为离散函数,您可以使用中心actionHandlers变量进行注册。这使得添加新命令几乎是微不足道的。如果您可以添加一些有关上述方法为什么不适合您的详细信息,请告诉我,我会修改答案。
答案 2 :(得分:0)
至少在我的用例中,ArtHare的解决方案阻止了后台执行,包括那些由诺言启动的后台执行。尽管这段代码不太好用,但它确实阻止了当前函数的执行,直到完成从stdin的读取为止。
尽管此代码必须从异步函数内部运行,但是请记住,从顶级上下文(直接从脚本而不是任何其他函数中包含)运行异步函数将阻止该功能,直到完成为止。
下面是演示用法的完整.js脚本,并已通过节点v8.12.0进行了测试:
const readline = require('readline');
const sleep = (waitTimeInMs) => new Promise(resolve => setTimeout(resolve, waitTimeInMs));
async function blockReadLine() {
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
terminal: false
});
let result = undefined;
rl.on('line', function(line){
result = line;
})
while(!result) await sleep(100);
return result;
}
async function run() {
new Promise(async () => {
while(true) {
console.log("Won't be silenced! Won't be censored!");
await sleep(1000);
}
});
let result = await blockReadLine();
console.log("The result was:" + result);
process.exit(0);
}
run();