[英]How to mix sync and async code in javascript in node.js and MongoDb
我有這段代碼:
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]);
}
您沒有得到預期輸出的原因是因為您正在共享所有數據庫調用的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();
}
使用的承諾,你可以promisify()
的db.news.findOne()
函數,以便它返回一個承諾,收集所有的比賽到一個數組,然后使用.reduce()
進行排序的所有數據庫與承諾的要求.then()
提供測序的方法。
你只得到最后一個href的原因是因為迭代並調用fineOne這是一個asyc操作。 雖然不會等到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-然后同步-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(){} );
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.