简体   繁体   English

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

[英]How to mix sync and async code in javascript in node.js and MongoDb

I have this code snippet: 我有这段代码:

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

Here is the sample output: 以下是示例输出:

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

So, I have three sets of data to be passed to findOne function. 所以,我有三组数据要传递给findOne函数。 However, only the last one got passed in three times. 但是,只有最后一个传递了三次。 How to workaround? 如何解决?

UPDATE based on jfriend00 and Neta Meta, these are the two ways to make it work: 更新基于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();

Or 要么

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

The reason you don't get the output you expect is because you're sharing the href and title variables for all your database calls. 您没有得到预期输出的原因是因为您正在共享所有数据库调用的hreftitle变量。 Thus, those aren't kept track of separately for each async database operation. 因此,对于每个异步数据库操作,不会单独跟踪那些。

If you're OK with all your async functions executing at once and the data can be processed in any order, then you just need to create a closure so capture your local variables separately for each invocation of the loop: 如果您可以立即执行所有异步函数并且可以按任何顺序处理数据,那么您只需要创建一个闭包,以便为每次循环调用单独捕获局部变量:

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

If you want to issue the requests serially (only one at a time), then you can't really use the while loop to control things because it's going to launch them all at once. 如果你想连续发出请求(一次只发一个),那么你就不能真正使用while循环来控制事情,因为它会立即启动它们。 I tend to use this type of design pattern with a next() local function instead of the while loop for serial operation: 我倾向于使用这种类型的设计模式与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();
}

Using promises, you could promisify() the db.news.findOne() function so it returns a promise, collect all the matches into an array and then use .reduce() to sequence all the database calls with the promise's .then() method providing the sequencing. 使用的承诺,你可以promisify()db.news.findOne()函数,以便它返回一个承诺,收集所有的比赛到一个数组,然后使用.reduce()进行排序的所有数据库与承诺的要求.then()提供测序的方法。

The reason you only get the last href is because while iterates and call fineOne which is an asyc operation. 你只得到最后一个href的原因是因为迭代并调用fineOne这是一个asyc操作。 while wont wait till the findOne finishes it just continue running by the time the findOne finishes while got to the end of the loop and that's why you're getting the same href. 虽然不会等到findOne完成它只是在findOne完成时继续运行,同时到达循环结束,这就是为什么你得到相同的href。

there are several ways you could do that, 1 promises(prefered in my opinion) - you will have to read about promisses to learn more. 有几种方法你可以做到这一点,1承诺(我认为优先) - 你必须阅读有关承诺以了解更多。 however checkout: https://github.com/petkaantonov/bluebird http://www.html5rocks.com/en/tutorials/es6/promises/ and http://promise-nuggets.github.io/articles/03-power-of-then-sync-processing.html 但结帐: 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 in another function and binding whatever you want to it ( not a good option but possible) 将异步函数包装在另一个函数中并绑定任何你想要的东西(不是一个好的选择,但可能)

// 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM