迭代异步函数

时间:2016-04-04 15:06:27

标签: node.js asynchronous

我有一个使用模块cherio从网站获取数据的函数。

现在我想在一个关键字数组上迭代这个函数,在名为stats的数组中收集中间结果,最后通过console.log()

每当我运行此脚本时,它会快速触发异步函数并打印一个空的stats数组。

现在我的问题是:我如何等待异步函数完成,以便在填充/完成时将数组打印到控制台。

我已经google了很多搜索堆栈溢出。似乎有很多方法可以实现我的目标,但节点中最惯用的方法是什么?

以下是解决问题的方法:

var request = require("request"),
    cheerio = require("cheerio"),
    base_url = "http://de.indeed.com/Jobs?q=";  // after equal sign for instance:   sinatra&l=

/* search syntax:
   - http://de.indeed.com/Jobs?q=node&l=berlin&radius=100
   - 
   - 
*/ 

// //
var search_words = ["django", "python", "flask", 
                    "rails", "ruby",
            "node", "javascript", "angularjs", "react",
            "java", "grails", "groovy",
            "php", "symfony", "laravel"
            ];

var counter = 0;
var stats = [];


function getStats(keyword) {
    url = base_url + keyword + "&l=";
    request(url, function(err, resp, body) {
    if(!err) {
        $ = cheerio.load(body);
        data = $("#searchCount")[0].children[0].data.split(" ").reverse()[0];

        stats.push([keyword, data]);
        counter++;
    }
    // list complete?
    if (counter === search_words.length) {
        console.log(stats);
    }
    });
}

for (var j=0; j<= search_words.length; j++) {
    getStats(search_words[j]);
}

3 个答案:

答案 0 :(得分:3)

Promise是处理异步操作的最佳解决方案。

&#13;
&#13;
Promise.all(search_words.map(function(keyword) {
  return new Promise(function(resolve, reject) {
    request(base_url + keyword + "&l=", function(err, resp, body) {
      if (err) {
        return reject(err);
      }
      $ = cheerio.load(body);
      resolve([keyword, $("#searchCount")[0].children[0].data.split(" ").reverse()[0]]);
    });
  });
})).then(function(stats) {
  console.log(stats);
});
&#13;
&#13;
&#13;

答案 1 :(得分:1)

我能想到的最常见的方法是使用像Q这样的承诺库。

npm install --save q

然后在您的代码中使用它:

var Q = require('q');
var requestFn = q.denodeify(request);

然后迭代你的值:

var promises = search_words.map(function(keyword) {
   url = base_url + keyword + "&l=";
   return requestFn(url);
});

Q.all(promises).then(function(values) {
    //values will contain the returned values from all requests (in array form)
}, function(rejects) {
   //rejected promises (with errors, for example) land here
});

来自Q的denodeify函数基本上将基于回调的函数转换为一个返回promise的函数(未来值的一个步骤,只要它在那里)。该函数是requestFn(为它找到一个更好的名字!)。所有这些承诺都收集在一个数组中,传递给Q.all以确保所有承诺都得到满足(如果一个被拒绝,其他承诺也被拒绝)。

如果这不是您的预期行为:有很多方法可以与优秀的Q库一起玩。请参阅文档:https://github.com/kriskowal/q

我没有对此代码进行防弹测试。你可能需要稍微玩一下,但它应该让你知道如何正确地做这样的事情。计数器上升通常是处理异步代码的一种非常不可靠的方式。

答案 2 :(得分:0)

除了用于解决问题的常用(和正确)方法之外,还有一些模块可以让您编写同步的代码,如果您真的想要的话。

尝试google for“nodejs synchronous”将某些链接发送到nodejs模块和/或方法,以便在nodejs中编写同步代码,但我认为它们仅对某些特定问题有用(我自己从未使用过它们)