我有一个Node.js Typescript程序,我正在尝试逐行解析大型CSV文件并异步处理这些行。更具体地说,我需要一个能够:
的功能一些要求和注意事项:
这是我已经开始工作的一些测试代码。 ObjectStream
是一个自定义Node.js变换,可将CSV行转换为对象。
function parseFileAsync(filePath: string): Promise<any> {
var doParseFileAsync = (filePath: string) => {
var streamDeferred = q.defer<Promise<any>[]>();
var promises: Promise<any>[] = [];
var propertyNames: string[] = [];
var stream = fs.createReadStream(filePath, { encoding: "utf8" })
.pipe(new LineStream({ objectMode: true }))
.pipe(new ObjectStream({ objectMode: true }));
stream.on("readable", () => {
var obj: Object;
while ((obj = stream.read()) !== null) {
console.log(`\nRead an object...`);
var operationDeferred = q.defer<any>();
operationDeferred.resolve(doSomethingAsync(obj));
promises.push(operationDeferred.promise);
}
});
stream.on("end", () => {
streamDeferred.resolve(promises);
});
return streamDeferred.promise;
}
return doParseFileAsync(filePath)
.then((result: Promise<any>[]) => {
return q.all(result);
});
}
parseFileAsync(filePath)
.done((result: any[]) => {
console.log(`\nFinished reading and processing the file:\n\t${result.toString()}`);
});
最后done
调用在流开始运行之前执行,因为parseFileAsync
立即满足空数组;流还没有机会推动任何承诺。
经过几天的搜索,我仍然不确定这样做的正确方法是什么。节点/ JavaScript专家:帮助?
代码已经更新,我的承诺现在正在发挥得非常好。但是,如果需要,我需要一种方法来挂钩流并取消该过程。我还需要一种方法来重试失败的任何操作。
答案 0 :(得分:1)
我在程序的架构中遇到了一些限制,这些限制不允许我像我想的那样自由地传递承诺。相反,我决定等到上一批完成后再开始新的承诺,而不是开始一堆承诺。这是我采取的方法:
将流内容分隔为自己接受连续令牌的函数。如果要读取更多数据,返回值将包含读取的数据以及延续令牌:
function readFile(filepath: string, lines: number, start: any): Promise<any> {
...
}
定义将运行可重试操作的函数。在此函数的主体内,从文件中检索并处理一大块数据。如果结果具有延续令牌,则“递归地”再次调用操作函数:
function processFile(filepath: string, next: any): Promise<any> {
var chunkSize = 1;
return readLines(filepath, chunkSize, next)
.then((result) => {
// Do something with `result.lines`
...
if (result.next) {
return parseFile(filepath, result.next);
}
});
}
瞧!长期运行的操作,可以在块上运行,并且很容易报告进度。