我正在创建一个机器人,当它收到消息时开始读取文本文件,并使用文件内容对消息进行响应。
不幸的是,我无法摆脱这个异步地狱,我只会得到错误,未定义或承诺
最后一个实验是这样:
const fs = require('fs');
const readline = require('readline');
// bot.listen("message").reply(responseText())
function readFile(file) {
var text = '';
var readInterface = readline.createInterface({
input: fs.createReadStream(file),
terminal: false
});
readInterface.on('line', function(line) {
linea = line.trim();
console.log(linea);
text += linea;
}).on('close', function() {
return text;
});
});
}
async function responseText() {
var content = await readFile("file.txt");
content.then(function(data) {
return data;
})
}
我想得到的是延迟响应,直到获得文件内容为止。 我知道该节点基于异步,但是我不知道该如何处理!
谢谢
答案 0 :(得分:0)
如果您想使用async-await
,则需要创建一个诺言并将其返回。
function readFile(file) {
return new Promise((res, rej) => {
try {
var text = '';
var readInterface = readline.createInterface({
input: fs.createReadStream(file),
terminal: false
});
readInterface
.on('line', function (line) {
linea = line.trim();
text += linea;
})
.on('close', function () {
res(text);
});
} catch(err){
rej(err)
}
});
}
答案 1 :(得分:0)
如果您使用express.js或基于它的任何框架,则可以将readstream管道传递给响应,因为express的响应是以以下内容开头的流:
const es = require('event-stream')
...
let getFileStream = path => (
fs.createReadStream(path)
.pipe(es.split())
.pipe(es.map(function (data, cb) {
cb(null
, inspect(JSON.parse(data)))
}))
);
router.get('/message', function (req, res, next) {
let file$ = getFileStream(yourFilePath)
file$.on('error', next).pipe(res)
})
如果需要转换文件内容,可以使用transform stream或如上例所示的同步事件流映射。想法是始终在流级别上处理文件内容,以避免必须将整个文件内容加载到内存中。
您实际上并不想将整个文件内容缓冲在内存中。在忙碌的一天中,使用大型文件可能会很快成为一个问题。您需要的是将文件流直接传输到浏览器。相同的原则适用于任何类型的消费者。
当然,如果该机制全部是内部机制,则只应沿文件路径传递或传递实际流,直到需要实际打开文件并对内容执行某些操作为止。在这种情况下,您将返回流工具箱,无论它是本机的node.js流API实现,事件流包还是某种可观察的库,例如rxjs。
答案 2 :(得分:0)
我在一个应用程序中遇到了类似的问题,该应用程序监视目录中的新文件,读取文件,并根据文件内容返回派生数据。我的阅读器功能基于来自nodejs文档的async example。仅在完全读取文件之后,才返回包含上下文的options
。
const { createReadStream } = require('fs')
const { createInterface } = require('readline')
const { once } = require('events')
// Reader.js
async function Reader (options) {
let { file, cb } = options
let fileStream = createReadStream(file)
const readInterface = createInterface({
input: fileStream,
crlfDelay: Infinity
})
readInterface.on('line', (line) => {
cb(line)
})
await once(readInterface, 'close')
return options
}
module.exports = Reader
然后我有了一个导入我的Reader并定义如何使用它的文件。我定义了一个回调函数来传递给line
事件监听器。我将回调绑定到传递给Reader函数的options对象。在里面
readFile
函数我确保return
到Reader的调用,这是一个承诺。
/**
* @desc callback to instruct what to do with each line read
*
* @param {*} line
*/
const readFileLine = function (line) {
linea = line.trim();
console.log(linea);
text += linea;
this.context += linea
}
/**
* @desc once the added file is ready to be processed read file line by line
* @listens {Event} listens for `process` event
*/
const readFile = (options) => {
return Reader(options)
}
/**
* @desc Call the file reader and do what you need with the reponse
*
*/
const getResponseFromFiles = (file) => {
const opts = {}
opts.cb = readFileLine.bind(opts)
opts.context = ''
opts.file = file
readFile(opts)
.then(data => {
process.exitCode = 0
console.log(data)
return data
})
.catch(err => {
process.exitCode = 1
console.log(err.message)
})
}