Node.js 如何获取同步读线,或;模拟;它是在nodejs中使用异步的吗?

Node.js 如何获取同步读线,或;模拟;它是在nodejs中使用异步的吗?,node.js,readline,Node.js,Readline,我想知道是否有一种简单的方法来获得“同步”读线,或者至少在node.js中获得同步I/O的外观 我用这样的东西,但很别扭 var readline = require('readline'); var rl = readline.createInterface({ input: process.stdin, output: process.stdout, terminal: false }); var i = 0; var s1 = ''; var s2 = ''; rl.on(

我想知道是否有一种简单的方法来获得“同步”读线,或者至少在node.js中获得同步I/O的外观

我用这样的东西,但很别扭

var readline = require('readline');
var rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
  terminal: false
});

var i = 0;
var s1 = '';
var s2 = '';

rl.on('line', function(line){
    if(i==0) { s1 = line; }
    else if(i==1) { s2 = line; }
    i++;
})

rl.on('close', function() {
    //do something with lines
})'
而不是这个,我宁愿它像这样简单

var s1 = getline(); // or "await getline()?"
var s2 = getline(); // or "await getline()?"
有用条件:

(a) 我不喜欢使用外部模块或/dev/stdiofilehandle,我正在向一个代码提交网站提交代码,但这些在那里不起作用

(b) 可以使用异步/等待或生成器

(c) 应该是基于行的


(d) 在处理之前不需要将整个stdin读入内存,因为我不知道需要多少字符串,所以我将它们全部放在一个数组中

如果您需要更详细的答案或我的答案不准确,请随时发表评论:

var readline = require('readline');
var rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
    terminal: false
});

var i = 0;
var strings = [];

rl.on('line', function(line) {
    // 2 lines below are in case you want to stop the interface after 10 lines
    // if (i == 9)
    //  rl.close()
    strings[i] = line
    i++
}).on('close', function() {
    console.log(strings)
})
// this is in case you want to stop the program when you type ctrl + C
process.on('SIGINT', function() {
    rl.close()
})

这里有一个例子,但它需要在给出结果之前阅读整个标准文本,然而这并不理想

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


function lineiterator() {
    var currLine = 0;
    var lines = [];
    return new Promise(function(resolve, reject) {

        rl.on('line', function (line){
            lines.push(line)
        })
        rl.on('close', function () {
            resolve({
                next: function() {
                    return currLine < lines.length ? lines[currLine++]: null;
                }
            });
        })
    })
}

使用生成器,您的示例如下所示:

var readline = require('readline');
var rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
  terminal: false
});

var i = 0;
var s1 = '';
var s2 = '';

var iter=(function* () {
    s1 = yield;
    i++;
    s2 = yield;
    i++;
    while (true) {
        yield;
        i++;
    }
})(); iter.next();
rl.on('line', line=>iter.next(line))

rl.on('close', function() {
    //do something with lines
})
因此,这里的
yield
就像是一个阻塞
getline()
一样,您可以按照通常的顺序方式处理行


UPD
异步/等待版本可能如下所示:

var readline = require('readline');
var rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
  terminal: false
});

var i = 0;
var s1 = '';
var s2 = '';

var continuation;
var getline = (() => {
    var thenable = {
        then: resolve => {
            continuation = resolve;
        }
    };
    return ()=>thenable;
})();
(async function() {
    s1 = await getline();
    i++;
    s2 = await getline();
    i++;
    while (true) {
        await getline();
        i++;
    }
})();
rl.on('line', line=>continuation(line))

rl.on('close', function() {
    //do something with lines
})

在这两个“同步”版本中,
i
不用于区分行,只用于计算行的总数。

试试这个。它仍然不是同步行读取函数的完美复制--例如,
async
函数仍然会在以后出现,因此您的一些调用代码可能会无序执行,你不能在正常的
for
循环中调用它,但它比典型的
on
问题
代码更容易阅读

// standard 'readline' boilerplate
const readline = require('readline');
const readlineInterface = readline.createInterface({
        input: process.stdin,
        output: process.stdout
});

// new function that promises to ask a question and 
// resolve to its answer
function ask(questionText) {
  return new Promise((resolve, reject) => {
    readlineInterface.question(questionText, (input) => resolve(input) );
  });
}

// launch your program since `await` only works inside `async` functions
start()

// use promise-based `ask` function to ask several questions
// in a row and assign each answer to a variable
async function start() {
  console.log()
  let name = await ask("what is your name? ")
  let quest = await ask("what is your quest? ")
  let color = await ask("what is your favorite color? ")
  console.log("Hello " + name + "! " + 
    "Good luck with " + quest + 
    "and here is a " + color + " flower for you.");
  process.exit() 
}
更新:实现它(这里的源代码:)。它还实现了其他一些功能,但它们似乎也很有用,而且没有太多的工程设计,不像其他一些声称做同样事情的NPM包。不幸的是,由于以下原因,我无法使其工作,但我喜欢它的中心功能的实现:

function ask(questionText) {
  return new Promise((resolve, reject) => {
    readlineInterface.question(questionText, resolve);
  });
}

readline
模块类似,还有另一个模块名为
readline sync
,它接受同步输入

例子:
以防万一将来有人在这里偶然发现

Node11.7使用异步等待添加了对此的支持

const readline = require('readline');
//const fileStream = fs.createReadStream('input.txt');

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

for await (const line of rl) {
  console.log(line)
}
请记住将其包装在异步函数中,否则将出现reserver\u关键字\u错误

要读取单个行,可以手动使用异步迭代器

const it = rl[Symbol.asyncIterator]();
const line1 = await it.next();

我想这就是你想要的:

const readline = require('readline');

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

const getLine = (function () {
    const getLineGen = (async function* () {
        for await (const line of rl) {
            yield line;
        }
    })();
    return async () => ((await getLineGen.next()).value);
})();

const main = async () => {
    let a = Number(await getLine());
    let b = Number(await getLine());
    console.log(a+b);
    process.exit(0);
};

main();

注意:这个答案使用了实验性的特性,需要节点v11.7,你可以把它包装成一个承诺-

const answer = await new Promise(resolve => {
  rl.question("What is your name? ", resolve)
})
console.log(answer)

@supersam654 I的可能重复添加了一些额外的条件以消除重复。我的条件是允许使用getline类型函数以干净的“同步”方式使用readline接口读取(单个)行,或者使用“异步/等待”函数进行模拟。这需要将整个stdin读取到内存中,我希望情况不是这样,因为我通过stdin读取大文件,需要流化它是一个流,所以它进入内存的唯一原因是因为我把它放在变量字符串中,但是如果你用它做其他事情,它就不会进入内存。但是我想要perl
my$line=
中的类似内容。或者C++中的GETLIN。这么难吗?我觉得我的请求并不奇怪,我想象它是通过生成器或异步/等待来完成的。真正的问题是你想对所有行做什么?目前,数据行通过stdin管道传输到程序中,数据通常有一些头行,然后是大量数据。标题没有信号,您只需根据问题的需要推断它,数据和标题包含字符串和数字的混合。因此,仅仅控制一个getline函数要比在on('line')回调中调整代码容易得多?例如,在循环之前,我想读一两行,所以我想说like const header=await rl.next(),但这即使在节点11.7@ColinDI中也不起作用。我发现这些答案的语法复杂性是不必要的复杂。我知道这是完全可行的,但我正在寻找一些简单的东西,比如
var h1=await rl.next();var h2=等待rl.next();对于await(rl的const行){/*处理文件的其余部分*/}
,但是正如我上面提到的,rl迭代器并没有提供它看起来是这样的!我明白了,vl检查readline和wait的
实现
@aishwatching当我使用你的代码时,我在wait的行上发现一个语法错误。意外标记,应为(您能验证它是否仍在工作吗?这看起来不错,例如,在添加这两个数字后,您如何设置一个循环以读取直到输入结束?如果到达EOF,getLine将返回undefined,因此当(1){let x=await getLine();如果(x==undefined)break;/*则使用x*/}这应该是这个问题的正确答案(这是最佳实践)@johannchopin不,这不是我想要的方法。我使用的是通过stdin或大型数据集的管道,而不是问答模块,这就是readline sync的设计目的。还有另一个模块叫做
readline async
,以防任何人需要承诺。我喜欢这个解决方案。使用承诺可以利用async/aw的强大功能ait上下文而不需要另一个库。我宁愿将readline接口作为参数传递给ask函数,以便您可以使用不同的接口。
const it = rl[Symbol.asyncIterator]();
const line1 = await it.next();
const readline = require('readline');

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

const getLine = (function () {
    const getLineGen = (async function* () {
        for await (const line of rl) {
            yield line;
        }
    })();
    return async () => ((await getLineGen.next()).value);
})();

const main = async () => {
    let a = Number(await getLine());
    let b = Number(await getLine());
    console.log(a+b);
    process.exit(0);
};

main();
const answer = await new Promise(resolve => {
  rl.question("What is your name? ", resolve)
})
console.log(answer)