简体   繁体   English

如何让 readline 等待异步承诺?

[英]How can I make a readline await async promise?

On NodeJS I need to make a grep like function for log research purposes and I'm trying to make it using readline (since I don't want readline-sync).在 NodeJS 上,我需要为日志研究目的创建一个类似 grep 的函数,我正在尝试使用 readline 来实现它(因为我不想要 readline-sync)。 I've read many messages, tutorials, documentation, stackoverflow posts, and so on, but I couldn't understood how to make it works.我已经阅读了许多消息、教程、文档、stackoverflow 帖子等,但我无法理解如何使其工作。

const grep = async function(pattern, filepath){
    return new Promise((resolve, reject)=>{
        let regex = new RegExp(pattern);
        let fresult = ``;

        let lineReader = require(`readline`).createInterface({
            input: require(`fs`).createReadStream(filepath)
        });

        lineReader.on(`line`, function (line) {
            if(line.match(regex)){
                fresult += line;
            }
        });

        resolve(fresult);
    });
}

let getLogs = await grep(/myregex/gi, filepath);
console.log(getLogs);

Which gives me:这给了我:

SyntaxError: await is only valid in async functions and the top level bodies of modules SyntaxError: await 仅在异步函数和模块的顶级主体中有效

Where am I wrong?我哪里错了? I feel like I'm good but did a beginner mistake which is dancing just under my eyes.我觉得我很好,但犯了一个初学者的错误,那就是在我的眼睛下跳舞。

What the other answers have missed is that you have two problems in your code.其他答案遗漏的是您的代码中有两个问题。

The error in your question:您问题中的错误:

Top level await ( await not wrapped in an async function) is only possible when running Node.js "as an ES Module", which is when you are using import {xyz} from 'module' rather than const {xyz} = require('module') .只有在“作为 ES 模块”运行 Node.js 时,才可能使用顶级 await( await未包含在async函数中),即当您使用import {xyz} from 'module'而不是const {xyz} = require('module')

As mentioned, one way to fix this is to wrap it in an async function:如前所述,解决此问题的一种方法是将其包装在异步函数中:

// Note: You omitted the ; on line 18 (the closing } bracket)
// which will cause an error, so add it.

(async () => {
let getLogs = await grep(/myregex/gi, filepath);
console.log(getLogs);
})();

A different option is to save your file as .mjs , not .js .另一种选择是将文件另存为.mjs ,而不是.js This means you must use import rather than require .这意味着您必须使用import而不是require

The third option is to create a package.json and specify "type": "module" .第三个选项是创建一个package.json并指定"type": "module" Same rules apply.相同的规则适用。

A more fundamental issue:一个更基本的问题:

When you call resolve() the event handler in lineReader.on('line') will not have been executed yet.当您调用resolve()lineReader.on('line') resolve()的事件处理程序还没有被执行。 This means that you will be resolving to an empty string and not the user's input.这意味着您将解析为空字符串而不是用户的输入。 Declaring a function async does nothing to wait for events/callbacks, after all.毕竟,声明一个函数async对等待事件/回调没有任何作用。

You can solve this by waiting for the 'close' event of Readline & only then resolve the promise.您可以通过等待 Readline 的“关闭”事件来解决此问题,然后才解决承诺。

const grep = async function(pattern, filepath){
    return new Promise((resolve, reject)=>{
        let regex = new RegExp(pattern);
        let fresult = ``;

        let lineReader = require(`readline`).createInterface({
            input: require(`fs`).createReadStream(filepath)
        });

        lineReader.on(`line`, function (line) {
            if(line.match(regex)){
                fresult += line;
            }
        });

        // Wait for close/error event and resolve/reject
        lineReader.on('close', () => resolve(fresult));
        lineReader.on('error', reject);
    });
}; // ";" was added

(async () => {
  let getLogs = await grep(/myregex/gi, 'foo');
  console.log("output", getLogs);
})();

A tip一个提示

The events module has a handy utility function named once that allows you to write your code in a shorter and clearer way: events模块有一个名为once的方便的实用程序函数once它允许您以更短更清晰的方式编写代码:

const { once } = require('events');
// If you're using ES Modules use: 
// import { once } from 'events'

const grep = async function(pattern, filepath){
    // Since the function is 'async', no need for 
    // 'new Promise()'

    let regex = new RegExp(pattern);
    let fresult = ``;

    let lineReader = require(`readline`).createInterface({
        input: require(`fs`).createReadStream(filepath)
    });

    lineReader.on(`line`, function (line) {
        if(line.match(regex)){
            fresult += line;
        }
    });

    // Wait for the first 'close' event
    // If 'lineReader' emits an 'error' event, this
    // will throw an exception with the error in it.
    await once(lineReader, 'close');
    return fresult;
};

(async () => {
  let getLogs = await grep(/myregex/gi, 'foo');
  console.log("output", getLogs);
})();

// If you're using ES Modules: 
// leave out the (async () => { ... })();

Wrap the function call into an async IIFE :将函数调用包装到异步IIFE 中

(async()=>{
  let getLogs = await grep(/myregex/gi, filepath);
  console.log(getLogs);
})()

try this:尝试这个:

async function run(){

let getLogs = await grep(/myregex/gi, `/`);
console.log(getLogs);
}

run();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM