如何在node.js和MongoDb中的JavaScript中混合同步和asynchronous代码

我有这个代码片段:

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的更新,这些是使它工作的两种方法:

 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]); } 

您没有得到您期望的输出的原因是因为您正在共享所有数据库调用的hreftitlevariables。 因此,对于每个asynchronous数据库操作,都不会单独跟踪。

如果您可以立即执行所有asynchronous函数,并且可以按任意顺序处理数据,那么您只需创build一个闭包,以便为每个循环调用分别捕获局部variables:

 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循环来控制事物,因为它将一次性启动它们。 我倾向于使用这种types的devise模式与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(); } 

使用承诺,你可以promisify() db.news.findOne()函数,以便它返回一个承诺,收集到一个数组的所有匹配,然后使用.reduce()sorting所有的数据库调用承诺的.then()提供测序的方法。

你只得到最后一个href的原因是因为迭代和调用fineOne这是一个asyc操作。 而不会等到findOne完成它只是继续运行的时候findOne完成,而到达循环的结束,这就是为什么你得到相同的href。

有几种方法可以做到这一点,1承诺(在我看来,首选) – 你必须阅读有关promisses了解更多。 但结帐: https : //github.com/petkaantonov/bluebird http://www.html5rocks.com/en/tutorials/es6/promises/和http://promise-nuggets.github.io/articles/03-power -of-然后同步-processing.html

用另一个函数包装你的asynchronous函数,并绑定任何你想要的(不是一个好的select,但可能)

 // 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(){} ); }