如何在node.js中对代码执行进行排序非阻塞代码?

时间:2014-08-26 14:53:55

标签: javascript node.js callback request nonblocking

我使用node.js构建了一个网络抓取工具,但是node.js的一个主要功能是Non-Blocking代码,这很棒,但在我的情况下它会破坏我的程序。以下是我的程序的工作方式:

  1. 首先,它为网站制作request并找到所有链接 所有通过该页面的公司;
  2. 然后我有for循环修改公司的URL数组;
  3. 然后我有for {循环中的request 一系列公司URL,用于查找每个公司中的所有产品URL 页;
  4. 然后我有for循环来修改那些产品的URL数组;
  5. 然后我有for循环中的另一个请求 抛出一系列产品并获得每种产品的价格 将它存储到字典(对象)中,其中键是名称 产品和价值是价格;
  6. 最后,我修改了我的词典(对象)。
  7. 正如您所看到的,我的每个步骤都取决于它之前的步骤。所以我需要做一些事情,所以我的程序按照我列出的顺序运行。我曾尝试使用callback,但它并没有很好地结束。因为这是callback

    的简单示例
    function some_function(arg1, arg2, callback) {
        var my_number = (arg1 - arg2) * arg2;
        callback(my_number);
    }
    
    some_function(20, 15, function(num) {
        console.log("callback called! " + num);
    });
    

    但我不认为如何进行具有6个功能的回调。也许有一种方法,但不是我对callback的了解。这是我的程序的演示版本,没有callback的:

    var request = require('request');
    var cheerio = require('cheerio');
    var companiesUrls = [];
    var url = '';
    var companiesUrls2 = [];
    var carsUrls = [];
    var carsOwnerReview = {};
    var carReviewUrl = [];
    var site = '...'
    var companiesPath = '/companies'
    ///step 1\\\
    request(site+companiesPath, function(err, resp, body){
        if(!err && resp.statusCode == 200){
            var $ = cheerio.load(body);
            $('a', '#group-content').each(function(){
                var url = $(this).attr('href');
                companiesUrls.push(url);
            });
        };
    });
    ///step 2\\\
    for(var i=0;i<companiesUrls.length;i+=2){
        companiesUrls2.push(companiesUrls[i]);
    };
    
    ///step 3\\\
    for(var i=0;i<companiesUrls2.length;i++){
        request(site+companiesUrls2[i], function(err, resp, body){
            if(!err && resp.statusCode == 200){
                var $ = cheerio.load(body);
                $('h3.edition-title').children().children().each(function(){
                    var url = $(this).attr('href');
                    carsUrls.push(url);
                });
            };
        });
    };
    ///step 4\\\
    for(var i=0;i<carsUrls.length;i++){
        carReviewUrl.push(carsUrls[carsUrls.length-1].slice(0,-7)+'/owner-reviews');
    };
    ///step 5\\\
    for(var i=0;i<carReviewUrl.length;i++){
        request(site+carReviewUrl[i], function(err, resp, body){
            if(!err && resp.statusCode == 200){
                var $ = cheerio.load(body);
                var model = $('#page-title').text();
                $('span.total-votes').children().each(function(){
                    var reviewNum = $(this).text();
                    carsOwnerReview[model] = reviewNum;
                });
            };
        });
    }
    ///step 6\\\
    var keysSorted = Object.keys(carsOwnerReview).sort(function(a,b){return carsOwnerReview[a]-carsOwnerReview[b]});
    var keysSortedReversed = keysSorted.reverse();
    

    所以我的问题是:如何在我的订单中使用node.js运行我的代码?

1 个答案:

答案 0 :(得分:0)

如果你想用JavaScript / node.js认真编程,你必须深刻理解JS是异步的,除了你的代码之外,一切都是并行的。

这意味着在您的情况下,除非您的所有代码都已终止,否则不会调用您的回调。因此,在for-loop中调用异步函数应始终将所有警告灯 RED

以下是您正确设计的代码:

var request = require('request');
var cheerio = require('cheerio');
var companiesUrls = [];
var url = '';
var companiesUrls2 = [];
var carsUrls = [];
var carsOwnerReview = {};
var carReviewUrl = [];
var site = '...'
var companiesPath = '/companies'


///step 1\\\
request(site+companiesPath, function(err, resp, body){
    if(!err && resp.statusCode == 200){
        var $ = cheerio.load(body);
        $('a', '#group-content').each(function(){
            var url = $(this).attr('href');
            companiesUrls.push(url);
        });
    };
    ///step 2\\\
    for(var i=0;i<companiesUrls.length;i+=2){
        companiesUrls2.push(companiesUrls[i]);
    };

    ///step 3\\\
    function processCompaniesUrls2( i, callback_pcu2 ) {
        if( i<companiesUrls2.length ) {
            request(site+companiesUrls2[i], function(err, resp, body){
                if(!err && resp.statusCode == 200){
                    var $ = cheerio.load(body);
                    $('h3.edition-title').children().children().each(function(){
                        var url = $(this).attr('href');
                        carsUrls.push(url);
                    });
                };
                processCompaniesUrls2( i+1, callback_pcu2 );
            });
        } else {
            callback_pcu2();
        }
    }
    processCompaniesUrls2( 0, function() {

        ///step 4\\\
        for(var i=0;i<carsUrls.length;i++){
            carReviewUrl.push(carsUrls[carsUrls.length-1].slice(0,-7)+'/owner-reviews');
        };
        ///step 5\\\
        function processCarReviewUrl( i, callback_pcru ) {
            if( i<carReviewUrl.length ) {
                request(site+carReviewUrl[i], function(err, resp, body){
                    if(!err && resp.statusCode == 200){
                        var $ = cheerio.load(body);
                        var model = $('#page-title').text();
                        $('span.total-votes').children().each(function(){
                            var reviewNum = $(this).text();
                            carsOwnerReview[model] = reviewNum;
                        });
                    };
                    processCarReviewUrl( i+1, callback_pcru );
                });
            } else {
                callback_pcru();
            }
        }
        processCarReviewUrl( 0, function() {
            ///step 6\\\
            var keysSorted = Object.keys(carsOwnerReview).sort(function(a,b){return carsOwnerReview[a]-carsOwnerReview[b]});
            var keysSortedReversed = keysSorted.reverse();
        });
    });
});

因为事情甚至会变得更复杂,所以我强烈推荐this article的研究。这真的值得一读。