知道我的功能何时结束

时间:2017-05-01 23:31:44

标签: javascript node.js callback

这是我的功能

function parseLinks(links, callback) {

    var products = [];
    for (var i = 0; i < links.length; i++) {
        request(links[i], function (error, response, body) {
            var product;
            if (!error && response.statusCode == 200) {
                var $ = cheerio.load(body);

                // title
                var title = $('h1').text();
                if (!title)
                    var title = $('title').text();

                var description = $('meta[name="description"]').attr('content');

                product = new Product(links[0].trim(), title.trim(), description.trim());
                products.push(product);
            }
        });
    }
    callback(products) // the callback only do a console.log(products)
}

之后,我想做一个显示所有产品的 console.log(产品)。 所以我设置了一个附加到parseLinks的回调,并在for循环后调用它。问题出在我的for循环中,我每次都调用异步函数 request ,所以在所有请求调用结束之前调用我的回调,所以我的控制台.log(产品)打印一个空数组。

你知道如何解决这个问题吗? 感谢

3 个答案:

答案 0 :(得分:1)

您必须检查是否所有异步调用都已完成。创建一个内部函数,在完成所有异步工作时调用callback

function parseLinks(links, callback) {
    var products = [],
        numberOfItems = links.length; // numbers of linkes to be parsed

    function checkIfDone() {          // this function will be called each time link is parsed
        numberOfItems--;              // decrement the numberOfItems (number that tells us how many links left)
        if(numberOfItems === 0)       // if there are none left (all links are parsed), then call callback with the resultant array.
            callback(products);
    }

    for (var i = 0; i < links.length; i++) {
        request(links[i], function (error, response, body) {
            // ...

            checkIfDone();            // everytime a link is parsed, call checkIfDone
        });
    }
}

您可以直接在函数checkIfDone中嵌入request的逻辑。为清楚起见,我使用了一个单独的功能。

答案 1 :(得分:0)

最好的方法是使用async

var async = require("async");

function parseLinks(links, callback) {

    var products = [];
    async.forEach(links, function(link, done) {
        request(link, function (error, response, body) {
            var product;
            if (!error && response.statusCode == 200) {
                var $ = cheerio.load(body);

                // title
                var title = $('h1').text();
                if (!title)
                    var title = $('title').text();

                var description = $('meta[name="description"]').attr('content');

                product = new Product(links[0].trim(), title.trim(), description.trim());
                products.push(product);
            }

            done();
        });
    }, function() {
        callback(products);
    });
}

答案 2 :(得分:0)

您可以使用async.each模块中的asnyc

简化代码:

function parseLinks(links, callback) {
    var products = [];

    async.each(links, function(link, requestCallback) {
        request(links[i], function(error, response, body) {
            //... rest of your code
            requestCallback(); //Request has ended
        });


    }, function(err) {
        //All requests ended!
        callback();
    });
}