【发布时间】:2016-02-08 20:14:59
【问题描述】:
我有一个长文本文件,我逐行循环以提取一些事件数据并将其存储在数据库中。该文件会定期更新顶部的新数据。发生这种情况时,我会再次运行文件以提取新事件,但是当我遇到数据库中已经存在的事件时我想停止(文件总是按从最新到最旧的顺序排列)。
使用this answer中描述的reduce()方法对问题Correct way to write loops for promise,我想出了这个函数来解析文件:
function parse(
file)
{
var lines = file.split("\n"),
latestDate;
return lines.reduce(function(promise, line) {
return promise.then(function() {
if (/* line matches date pattern */) {
latestDate = line;
} else if (/* line matches event pattern */) {
return Event.createAsync(line, latestDate);
}
return promise;
});
}, Promise.resolve())
.catch({ errorName: "uniqueViolated" },
function() { /* ignore only the createAsync error */ });
}
createAsync() 数据库方法返回一个在保存事件时解决的承诺。如果数据库中已经存在该事件,它将引发异常,这会停止承诺链,因此不会解析文件的其余部分。该异常被函数末尾的catch() 处理程序捕获并忽略。我在 Node.js 中使用 Bluebird 3.0 承诺库。
此函数会依次循环遍历每一行,并在遇到已保存的事件时正确停止。但我想知道这是否是在处理承诺时打破循环的最佳方式。在函数末尾吞下抛出的异常似乎有点笨拙。
欢迎提出任何改进循环处理的建议。
解决方案?
以jib's answer 为基础,并考虑到Bergi's comment,也许我应该尝试他对我链接到的问题的非简化答案:),我想出了这个解决方案:
function parse(
file)
{
var lines = file.split("\n"),
latestDate;
return promiseEach(lines, function(line) {
if (/* line matches date pattern */) {
latestDate = line;
} else if (/* line matches event pattern */) {
return Event.createAsync(line, latestDate)
.catch({ errorType: "uniqueViolated" }, function() { return false; });
}
});
}
循环递归被移到一个通用函数promiseEach() 中,该函数循环遍历数组中的每个项目。如果迭代器函数返回一个 Promise,则在该 Promise 解决之前不会处理下一项。如果迭代器返回false,则循环结束,Lo-dash 样式:
function promiseEach(
list,
iterator,
index)
{
index = index || 0;
if (list && index < list.length) {
return Promise.resolve(iterator(list[index])).then(function(result) {
if (result !== false) {
return promiseEach(list, iterator, ++index);
}
});
} else {
return Promise.resolve();
}
}
我认为这可以满足我的要求,但我想知道如果我在 4000 行文件上运行它是否会出现调用堆栈问题。
【问题讨论】:
-
我会按名称检查来自
createAsync的特定错误,如果不同,则在catch中重新抛出错误。吞下所有错误是不好的。 -
谢谢。我使用新的 Bluebird 3.0 对象谓词语法将
.error()更改为.catch(),因此它应该只会吞下createAsync()引发的错误。我的问题仍然是依赖抛出的异常是否是一种合理的跳出循环的方法,或者是否有更规范的方法。 -
抛出异常(或返回被拒绝的承诺)不仅是合理的,而且是唯一打破 .then 链(而不是构建它的循环)的方式。
-
您可能只是尝试使用非
reduce方法来回答您链接的问题的其他答案:-)
标签: javascript node.js promise bluebird