迭代asynchronous函数

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

现在我想通过关键字数组遍历这个函数,在一个名为stats的数组中收集中间结果,最后通过console.log()将stats数组的结果打印到控制台。

每当我运行这个脚本时,它会很快触发asynchronous函数并打印一个空的stats数组。

现在我的问题:我如何等待asynchronous函数完成,以便我可以打印数组到控制台,当它填充/完成。

我search了很多,search堆栈溢出。 似乎有很多方法可以实现我的目标,但是在这个节点中最习惯的方式是什么呢?

这是我解决这个问题的方法:

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

Promise是处理asynchronous操作的最佳解决scheme。

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

我能想到的最常见的方式是使用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函数基本上将基于callback的函数转换为一个返回promise的函数(只要它在那里,就会引入未来的值)。 该函数是requestFn(find一个更好的名字!)。 所有这些承诺都被收集在一个数组中,这个数组被传递给Q.all以确保所有的承诺都被履行(如果被拒绝,其他的承诺也被拒绝)。

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

我没有防弹testing这个代码。 你可能需要稍微玩一下,但是它应该给你一个关于如何完美地做这样的事情的好主意。 有一个计数器往往是一个非常不可靠的方式处理asynchronous代码。

其他通常(和正确)的方式,你用来解决这个问题,有一些模块,让你写代码是同步的,如果你真的想。

尝试谷歌的“nodejs同步”作为结果给一些链接到nodejs模块和/或方法在nodejs编写同步代码,但我想他们是有用的只有一些特定的问题(从来没有用过他们自己)