等待用户在 Node.js 中输入

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18193953/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 15:17:54  来源:igfitidea点击:

Waiting for user to enter input in Node.js

node.js

提问by blandish

I understand the rationale in Node.js for asynchronous events and I am learning how to write code that way. However, I am stuck with the following situation:

我了解 Node.js 中异步事件的基本原理,并且我正在学习如何以这种方式编写代码。但是,我遇到了以下情况:

I want to write code that occasionally pauses for user input.

我想编写偶尔为用户输入暂停的代码。

The program is not intended as a server (though currently it's intended for the command line). I realize this is an atypical use of Node. My goal is to eventually migrate the program back to a client-side Javascript application, but I find working in Node.js to be both fascinating and very useful for debugging. This brings me back to my example that illustrates the problem:

该程序不打算用作服务器(尽管目前它是用于命令行的)。我意识到这是 Node.js 的一种非典型用法。我的目标是最终将程序迁移回客户端 Javascript 应用程序,但我发现在 Node.js 中工作既有趣又对调试非常有用。这让我回到了说明问题的示例:

It reads in a text file and outputs each line unless the line ends with a "?". In that case, it should pause for user to clarify what was meant by that line. Currently my program outputs all lines first and waits for the clarifications at the end.

它读入一个文本文件并输出每一行,除非该行以“?”结尾。在这种情况下,它应该暂停让用户澄清该行的含义。目前我的程序首先输出所有行,然后等待最后的澄清。

Is there any way to force node.js to pause for command-line input precisely for the cases where the conditional fires (i.e., where the line ends with a "?")?

有什么方法可以强制 node.js 在条件触发的情况下(即,行以“​​?”结尾)精确地暂停命令行输入?

var fs = require("fs");
var filename = "";
var i = 0;
var lines = [];

// modeled on http://st-on-it.blogspot.com/2011/05/how-to-read-user-input-with-nodejs.html
var query = function(text, callback) {
    process.stdin.resume();
    process.stdout.write("Please clarify what was meant by: " + text);
    process.stdin.once("data", function(data) {
        callback(data.toString().trim());
    });
};

if (process.argv.length > 2) {
    filename = process.argv[2];
    fs.readFile(filename, "ascii", function(err, data) {
        if (err) {
            console.error("" + err);
            process.exit(1);
        }
        lines = data.split("\n");
        for (i = 0; i < lines.length; i++) {
            if (/\?$/.test(lines[i])) { // ask user for clarification
                query(lines[i], function(response) {
                    console.log(response);
                    process.stdin.pause();
                });
            }
            else {
                console.log(lines[i]);
            }
        }
    });
}
else {
    console.error("File name must be supplied on command line.");
    process.exit(1);
}  

回答by mpen

Here's another way that has no dependencies (readlineis built-in)

这是另一种没有依赖关系的方式(readline是内置的)

const readline = require('readline');

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

    return new Promise(resolve => rl.question(query, ans => {
        rl.close();
        resolve(ans);
    }))
}


const ans = await askQuestion("Are you sure you want to deploy to PRODUCTION? ");

回答by ChrisCM

The trick is to not do it itteratively, but do the for loop recursively. So that the next line is printOut in a callback, that is called either A: after the line gets printed, or B: after the console input has been processed.

诀窍是不要迭代地执行它,而是递归地执行 for 循环。因此,下一行是回调中的 printOut,即在该行打印后调用 A: 或在处理控制台输入后调用 B:。

var fs = require("fs");

// modeled on http://st-on-it.blogspot.com/2011/05/how-to-read-user-input-with-nodejs.html
function query(text, callback) {
    'use strict';
    process.stdin.resume();
    process.stdout.write("Please clarify what was meant by: " + text);
    process.stdin.once("data", function (data) {
        callback(data.toString().trim());
    });
}

function printLinesWaitForQuestions(lines, someCallbackFunction) {
    'use strict';

    function continueProcessing() {
        if (lines.length) {
            printNextLine(lines.pop());
        } else {
            someCallbackFunction();
        }
    }

    function printNextLine(line) {

        if (/\?$/.test(line)) { // ask user for clarification
            query(line, function (response) {
                console.log(response);
                process.stdin.pause();
                continueProcessing();
            });
        } else {
            console.log(line);
            continueProcessing();
        }
    }

    continueProcessing();
}

if (process.argv.length > 2) {
    var filename = process.argv[2];
    fs.readFile(filename, "ascii", function (err, data) {
        'use strict';

        if (err) {
            console.error("" + err);
            process.exit(1);
        }

        var lines = data.split("\n");
        printLinesWaitForQuestions(lines, function () {
            console.log('Were done now');
        });
    });
} else {
    console.error("File name must be supplied on command line.");
    process.exit(1);
}

This is a good solution for two reasons:

这是一个很好的解决方案,原因有两个:

  1. It's relatively clean and the entire process can be contained within its own function closure, potentially leading to modularization.

  2. It doesn't break other asynchronous things you may want to do.

    There is no iterative waiting for loop and only one async task being launched per array of lines that you have. What if, in your version, you had millions of lines? You would have spun up millions of async outputs instantaneously... BAD!

    The recursive method not only allows better concurrency of other async work you want to do, but you don't clog the event loop with mini async tasks from one function call. This can cause memory issues, performance degradation, and other issues worthy of avoiding, particularly on large inputs.
  1. 它相对干净,整个过程可以包含在它自己的函数闭包中,可能会导致模块化。

  2. 它不会破坏您可能想做的其他异步事情。

    没有迭代等待循环,每个行数组只启动一个异步任务。如果在您的版本中,您有数百万行呢?你会立即启动数百万个异步输出......糟糕!

    递归方法不仅可以让您想要执行的其他异步工作更好地并发,而且您不会因为一个函数调用中的微型异步任务而阻塞事件循环。这可能会导致内存问题、性能下降和其他值得避免的问题,尤其是在大输入上。

回答by user3413723

I found a module that does this really easily for yes or no:

我找到了一个模块,它可以很容易地为是或否做到这一点:

https://www.npmjs.com/package/cli-interact

https://www.npmjs.com/package/cli-interact

Install: npm install cli-interact --save-dev

安装: npm install cli-interact --save-dev

How to use is taken straight from the npm site:

使用方法直接取自 npm 站点:

var query = require('cli-interact').getYesNo;
var answer = query('Is it true');
console.log('you answered:', answer);