如何让 readline 等待异步承诺?
How can I make a readline await async promise?
在 NodeJS 上,我需要为日志研究目的创建一个类似 grep 的函数,并且我正在尝试使用 readline 来实现它(因为我不想要 readline-sync)。我已经阅读了很多消息、教程、文档、Whosebug 帖子等等,但我不明白如何让它发挥作用。
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);
这给了我:
SyntaxError: await is only valid in async functions and the top level bodies of modules
我哪里错了?我觉得我很好,但犯了一个初学者的错误,在我眼皮底下跳舞。
将函数调用包装成异步 IIFE:
(async()=>{
let getLogs = await grep(/myregex/gi, filepath);
console.log(getLogs);
})()
试试这个:
async function run(){
let getLogs = await grep(/myregex/gi, `/`);
console.log(getLogs);
}
run();
其他答案遗漏的是您的代码中有两个问题。
你问题中的错误:
只有当 运行 Node.js “作为 ES 模块”时,才可能出现顶级等待(await
未包含在 async
函数中),也就是当您使用 import {xyz} from 'module'
而不是 const {xyz} = require('module')
.
如前所述,解决此问题的一种方法是将其包装在异步函数中:
// 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);
})();
另一种选择是将文件另存为 .mjs
,而不是 .js
。这意味着您必须使用 import
而不是 require
.
第三个选项是创建一个package.json
并指定"type": "module"
。同样的规则适用。
一个更根本的问题:
当您调用 resolve()
时,lineReader.on('line')
中的事件处理程序尚未执行。这意味着您将解析为一个空字符串,而不是用户的输入。毕竟,声明一个函数 async
不会等待 events/callbacks。
您可以通过等待 Readline 的 'close' 事件来解决此问题,然后再解决承诺。
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);
})();
小费
events
模块有一个名为 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 () => { ... })();
在 NodeJS 上,我需要为日志研究目的创建一个类似 grep 的函数,并且我正在尝试使用 readline 来实现它(因为我不想要 readline-sync)。我已经阅读了很多消息、教程、文档、Whosebug 帖子等等,但我不明白如何让它发挥作用。
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);
这给了我:
SyntaxError: await is only valid in async functions and the top level bodies of modules
我哪里错了?我觉得我很好,但犯了一个初学者的错误,在我眼皮底下跳舞。
将函数调用包装成异步 IIFE:
(async()=>{
let getLogs = await grep(/myregex/gi, filepath);
console.log(getLogs);
})()
试试这个:
async function run(){
let getLogs = await grep(/myregex/gi, `/`);
console.log(getLogs);
}
run();
其他答案遗漏的是您的代码中有两个问题。
你问题中的错误:
只有当 运行 Node.js “作为 ES 模块”时,才可能出现顶级等待(await
未包含在 async
函数中),也就是当您使用 import {xyz} from 'module'
而不是 const {xyz} = require('module')
.
如前所述,解决此问题的一种方法是将其包装在异步函数中:
// 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);
})();
另一种选择是将文件另存为 .mjs
,而不是 .js
。这意味着您必须使用 import
而不是 require
.
第三个选项是创建一个package.json
并指定"type": "module"
。同样的规则适用。
一个更根本的问题:
当您调用 resolve()
时,lineReader.on('line')
中的事件处理程序尚未执行。这意味着您将解析为一个空字符串,而不是用户的输入。毕竟,声明一个函数 async
不会等待 events/callbacks。
您可以通过等待 Readline 的 'close' 事件来解决此问题,然后再解决承诺。
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);
})();
小费
events
模块有一个名为 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 () => { ... })();