Node.js 迭代异步函数
我有一个使用cherio模块从网站获取数据的功能 现在我想在一个关键字数组上迭代这个函数,在一个名为stats的数组中收集中间结果,最后通过console.log()将stats数组的结果打印到控制台 每当我运行这个脚本时,它都会快速触发异步函数并打印一个空的stats数组 现在我的问题是:如何等待异步函数完成,以便在填充/完成阵列时将其打印到控制台 我在谷歌上搜索了很多,搜索了堆栈溢出。似乎有很多方法可以实现我的目标,但是node中最惯用的方法是什么呢 以下是我解决问题的方法:Node.js 迭代异步函数,node.js,asynchronous,Node.js,Asynchronous,我有一个使用cherio模块从网站获取数据的功能 现在我想在一个关键字数组上迭代这个函数,在一个名为stats的数组中收集中间结果,最后通过console.log()将stats数组的结果打印到控制台 每当我运行这个脚本时,它都会快速触发异步函数并打印一个空的stats数组 现在我的问题是:如何等待异步函数完成,以便在填充/完成阵列时将其打印到控制台 我在谷歌上搜索了很多,搜索了堆栈溢出。似乎有很多方法可以实现我的目标,但是node中最惯用的方法是什么呢 以下是我解决问题的方法: var req
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]);
}
var request=require(“请求”),
cheerio=需要(“cheerio”),
基本url=”http://de.indeed.com/Jobs?q="; // 在等号之后,例如:sinatra&l=
/*搜索语法:
- http://de.indeed.com/Jobs?q=node&l=berlin&radius=100
-
-
*/
// //
var search_words=[“django”、“python”、“flask”,
“rails”,“ruby”,
“节点”、“javascript”、“angularjs”、“react”,
“java”、“grails”、“groovy”,
“php”、“symfony”、“laravel”
];
var计数器=0;
var stats=[];
函数getStats(关键字){
url=base_url+关键字+“&l=”;
请求(url、函数(错误、响应、正文){
如果(!err){
$=cheerio.load(车身);
data=$(“#searchCount”)[0]。子项[0]。data.split(“”)。reverse()[0];
push([关键字,数据]);
计数器++;
}
//列表完成了吗?
如果(计数器===搜索单词长度){
console.log(stats);
}
});
}
对于(var j=0;j其他通常(也是正确的)解决问题的方法,如果您真的需要,有一些模块可以让您编写同步代码
尝试在谷歌上搜索“nodejs synchronous”,结果是提供一些指向nodejs模块和/或方法的链接,以便在nodejs中编写同步代码,但我认为它们仅适用于某些特定问题(我本人从未使用过)是处理异步操作的最佳解决方案
Promise.all(搜索词.map(函数(关键字)){
返回新承诺(功能(解决、拒绝){
请求(base_url+关键字+“&l=”,函数(err,resp,body){
如果(错误){
退货拒绝(err);
}
$=cheerio.load(车身);
解析([关键字,$(“#搜索计数”)[0]。子项[0]。数据。拆分(“”。反转()[0]]);
});
});
})).then(函数(统计){
console.log(stats);
})
我能想到的最常见的方法是使用像Q这样的promise库
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函数基本上将基于回调的函数转换为一个返回承诺的函数(一旦有了承诺,就立即返回未来值)。该函数是requestFn(为它找到更好的名称!)。所有这些承诺都收集在一个数组中,并传递给Q.All,以确保所有承诺都得到履行(如果一个承诺被拒绝,其他承诺也会被拒绝)
如果这不是您的预期行为:有很多方法可以使用优秀的Q库。请参阅文档:
我没有对这段代码进行防弹测试。您可能需要对它进行一点研究,但它应该能让您很好地了解如何合理地执行类似的操作。计数器上升通常是处理异步代码的一种非常不可靠的方式。谢谢您的回答。我知道它们是异步的。-我想知道最重要的是什么惯用的方法就是解决这个问题。-我必须嵌套两个函数吗?基本上是的。或者你可以使用一些nodejs模块(比如synchronize.js或node sync)这允许你序列化调用。但是正如我所说,我自己从来没有使用过这些模块,所以我真的不知道它们是否适合你的问题现在我应该如何嵌套迭代和异步函数?哪种迭代允许我等待回调的结果?我指定的模块有自己的语法来编写代码,所以你可以应该看看你可能决定使用的模块的文档。我刚刚运行了你的代码,它工作得很好。当然这不是一个好的解决方案,但工作得很好。这我非常喜欢!谢谢。顺便问一下:参数resolve和reject到底是什么?我看到它们被称为函数。“return reject(err);”和“resolve([关键字…”。但如果这两个参数本身就是函数:它们在哪里定义?我的意思是数组统计数据的附加实际上在哪里完成?@Ugur我建议您阅读本文,了解有关Promise Upvoting的更多信息,如果您喜欢,将不胜感激;)我很乐意。但是stackoverflow说我至少需要15点声誉积分