我有这段代码:
var re = new RegExp("<a href=\"(news[^?|\"]+).*?>([^<]+)</a>", "g");
var match;
while (match = re.exec(body)){
var href = match[1];
var title = match[2];
console.log(href);
db.news.findOne({ title: title }, function(err, result){
if (err) {
console.log(err);
} else {
console.log(href);
// more codes here
}
});
}
以下是示例输出:
news/2015/02/20/347332.html
news/2015/02/19/347307.html
news/2015/02/19/347176.html
news/2015/02/19/347176.html
news/2015/02/19/347176.html
news/2015/02/19/347176.html
所以,我有三组数据要传递给findOne函数。但是,只有最后一个传递了三次。如何解决?
基于jfriend00和Neta Meta的UPDATE,这两种方法可以让它发挥作用:
var re = new RegExp("<a href=\"(news[^?|\"]+).*?>([^<]+)</a>", "g");
var cnt = 0;
function next(){
var match = re.exec(body);
if (match) {
var href = match[1];
var title = match[2];
db.news.findOne({ title: title }, function(err, result){
if (err) {
console.log(err);
} else {
console.log(href);
// more codes here
}
});
}
}
next();
或者
var asyncFunction = function(db, href, title){
db.news.findOne({ title: title }, function(err, result){
if (err) {
console.log(err);
} else {
console.log(href);
// more codes here
}
});
}
var re = new RegExp("<a href=\"(news[^?|\"]+).*?>([^<]+)</a>", "g");
var match;
var cnt = 0;
while (match = re.exec(body)) {
asyncFunction(db, match[1], match[2]);
}
答案 0 :(得分:2)
您没有得到预期输出的原因是因为您正在共享所有数据库调用的href
和title
变量。因此,对于每个异步数据库操作,不会单独跟踪它们。
如果您可以立即执行所有异步函数并且可以按任何顺序处理数据,那么您只需要创建一个闭包,以便为每次循环调用分别捕获局部变量:
var re = new RegExp("<a href=\"(news[^?|\"]+).*?>([^<]+)</a>", "g");
var match, cntr = 0;
while (match = re.exec(body)){
(function(href, title, index) {
console.log(href);
db.news.findOne({ title: title }, function(err, result){
if (err) {
console.log(err);
} else {
console.log(href);
// more codes here
}
});
})(match[1], match[2], cntr++);
}
如果你想连续发出请求(一次只发一个),那么你就不能真正使用while
循环来控制事物,因为它会立即启动它们。我倾向于使用这种类型的设计模式,使用next()
本地函数而不是while
循环进行串行操作:
function someFunction() {
var re = new RegExp("<a href=\"(news[^?|\"]+).*?>([^<]+)</a>", "g");
function next() {
var match = re.exec(body);
if (match) {
var href = match[1];
var title = match[2];
db.news.findOne({ title: title }, function(err, result){
if (err) {
console.log(err);
} else {
console.log(href);
// more codes here
// launch the next iteration
next();
}
});
}
}
// run the first iteration
next();
}
使用promises,您可以promisify()
db.news.findOne()
函数,以便它返回一个promise,将所有匹配收集到一个数组中,然后使用.reduce()
对所有数据库调用进行排序提供排序的.then()
方法。
答案 1 :(得分:1)
你只得到最后一个href的原因是因为迭代并调用了一个asyc操作的fineOne。虽然不会等到findOne完成它只是在findOne完成时继续运行,同时到达循环结束,这就是为什么你得到相同的href。
有几种方法可以做到这一点,1个承诺(我认为是优先考虑的) - 你必须阅读有关承诺才能了解更多信息。但结帐: https://github.com/petkaantonov/bluebird http://www.html5rocks.com/en/tutorials/es6/promises/ 和 http://promise-nuggets.github.io/articles/03-power-of-then-sync-processing.html
将异步函数包装到另一个函数中并绑定任何你想要的东西(不是一个好的选择,但可能)
// wrapping your async function.
var asyncFunction = function(title,href, successCb, failCb){
db.news.findOne({ title: title }, function(err, result){
if (err) {
failCb();
} else {
successCb()
}
});
};
var re = new RegExp("<a href=\"(news[^?|\"]+).*?>([^<]+)</a>", "g");
var match;
while (match = re.exec(body)){
var href = match[1];
var title = match[2];
asyncFunction.call(this,title, href, function success(){}, function fail(){} );
}