2011-11-14 61 views
94

我认为使用一些控制台扩展来制作一个简单的服务器http服务器。我找到了从命令行数据读取的片段。我不能简单地使用while(done) { }循环吗?同样,如果服务器在问题时间接收到输出,它就会毁掉这条线。交互式地从控制台读取值

+1

我用'rl'表示你的意思是[readline](https://stackoverflow.com/a/14513763/712526)? – jpaugh

回答

109

你不能做一个“while(done)”循环,因为这需要阻塞输入,而node.js并不喜欢这样做。

而是建立一个回调每次进入时的东西被称为:

var stdin = process.openStdin(); 

stdin.addListener("data", function(d) { 
    // note: d is an object, and when converted to a string it will 
    // end with a linefeed. so we (rather crudely) account for that 
    // with toString() and then trim() 
    console.log("you entered: [" + 
     d.toString().trim() + "]"); 
    }); 
+1

谢谢这个作品,“最终”的听众是否允许打电话给一些关闭操作并说'再见'? –

+0

我从这个例子中删除了“最终”的听众,我不知道说实话会有用。 – rob

+0

如何用if语句控制类型化数据?或swtich情况? –

72

我用于此目的的另一个API ..

var readline = require('readline'); 
var rl = readline.createInterface(process.stdin, process.stdout); 
rl.setPrompt('guess> '); 
rl.prompt(); 
rl.on('line', function(line) { 
    if (line === "right") rl.close(); 
    rl.prompt(); 
}).on('close',function(){ 
    process.exit(0); 
}); 

这使得循环提示,直到答案是right。此外,它还提供了一个漂亮的小控制台。你可以找到详细信息@http://nodejs.org/api/readline.html#readline_example_tiny_cli

+5

这是一个很好的答案。什么可能不明显(但是是一个很大的优点)是readline不是外部依赖:它是node.js的一部分。 – jlh

22

自12'以来,Readline API已经发生了很大的变化。该文档的秀有用的例子,从一个标准流捕获用户输入:

const readline = require('readline'); 

const rl = readline.createInterface({ 
    input: process.stdin, 
    output: process.stdout 
}); 

rl.question('What do you think of Node.js? ', (answer) => { 
    console.log('Thank you for your valuable feedback:', answer); 
    rl.close(); 
}); 

More information here.

+2

这只是一个基本的例子。你如何互动?提问/回答?多种选择之类的?如果一旦关闭,如何重新打开rl,如果不能如何使用打开的rl与用户进行交互,包括一些逻辑 –

8

@rob答案将工作大部分的时间,但你期望有长的投入可能无法正常工作。

这是你应该使用什么来代替:为什么这个解决方案的工作

const stdin = process.openStdin(); 
let content = ''; 

stdin.addListener('data', d => { 
    content += d.toString(); 
}); 

stdin.addListener('end',() => { 
    console.info(`Input: ${content}`); 
}); 

说明:

addListener('data')的作品就像一个缓冲区,回调将被调用时,它是完全或/和它的输入结束。

那么长输入呢?一个'data'回调将不够用,因此它会将输入拆分为两个或多个部分。这往往不方便。

addListener('end')将在stdin读取器完成读取输入时通知我们。由于我们已经存储了以前的数据,现在我们可以一起阅读和处理它们。

8

请使用readline-sync,这可让您使用同步控制台而无需回调地狱。即使有密码的工作原理:

var favFood = read.question('What is your favorite food? ', { 
 
    hideEchoBack: true // The typed text on screen is hidden by `*` (default). 
 
});

+0

这需要额外的依赖性,所以我更喜欢其他解决方案。 –

2

我相信这值得现代async-await答案,假设节点> = 7.x中被使用。

答案仍然使用ReadLine::question但包装它,使while (done) {}是可能的,这是OP要求明确地。

var cl = readln.createInterface(process.stdin, process.stdout); 
var question = function(q) { 
    return new Promise((res, rej) => { 
     cl.question(q, answer => { 
      res(answer); 
     }) 
    }); 
}; 

然后用法的例子

(async function main() { 
    var answer; 
    while (answer != 'yes') { 
     answer = await question('Are you sure? '); 
    } 
    console.log('finally you are sure!'); 
})(); 

导致下面的谈话

Are you sure? no 
Are you sure? no 
Are you sure? yes 
finally you are sure! 
0

最常用的情况很可能是为应用程序显示一个通用的提示,并在处理它switch语句。

您可以通过使用一个辅助函数,将调用自身回调获得行为等同于while循环:

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

function promptInput (prompt, handler) 
{ 
    rl.question(prompt, input => 
    { 
     if (handler(input) !== false) 
     { 
      promptInput(prompt, handler); 
     } 
     else 
     { 
      rl.close(); 
     } 
    }); 
} 

promptInput('app> ', input => 
{ 
    switch (input) 
    { 
     case 'my command': 
      // handle this command 
      break; 
     case 'exit': 
      console.log('Bye!'); 
      return false; 
    } 
}); 

您可以传递的,而不是'app> '一个空字符串,如果您的应用程序已经打印的东西此循环之外的屏幕。