我正在使用请求和cheerio节点模块来创建从网站获取一些数据。 我想获得一个项目列表,一旦这个列表完成,就调用一个异步函数:
request('http://myurl', function(req,res,data){
var $ = cheerio.load(data);
var List = [];
$('.myItems').each(function(i, element){
console.log( typeof $(this).text() )
List.push($(this).text());
});
for (var i=0; i < List.length; i++){
// make an asynchronous call to a API
}
});
我的问题是我如何等待列表完成,即我怎么知道.each函数已遍历所有项目?
我可以使用异步执行此操作吗?
由于
答案 0 :(得分:12)
cheerio的.each
功能是同步的(参见source)。因此,只要您在回调中不执行任何异步操作(问题中就是这种情况),就无需执行任何操作:在以下行中,循环将完成。
如果做在循环中调用异步函数,最简洁和最简单的解决方案是使用Promise库。
以顺序方式(例如Bluebird):
var p = Promise.resolve();
$('.myItems').each(function(i, element){
p = p.then(function(){
// do something with $(this).text() and return a promise
});
});
p.then(function(){
// all asynchronous tasks are finished
});
如果不需要顺序请求(此处为Q示例):
Q.allSettled($('.myItems').map(function(){
// return a promise
})).then(function(){
// all asynchronous tasks are finished
});
答案 1 :(得分:1)
您可以使用async模块轻松处理这些异步任务。
具体而言async.each或async.eachLimit如果您需要并发&gt; 1或async.eachSeries如果你想要一次一个地浏览数组中的项目。
答案 2 :(得分:1)
我必须承认我没有设法让DenysSéguret的解决方案正常工作(对于.each()循环中的异步调用) - “after”操作仍然在.each()循环完成之前发生,但是我发现了一种不同的方式,我希望它有所帮助:
var Promises = require('bluebird');
request('http://myurl', function(req,res,data){
var $ = cheerio.load(data);
var List = [];
Promises
// Use this to iterate serially
.each($('.myItems').get(), function(el){
console.log( typeof $(el).text() )
List.push($(el).text());
})
// Use this if order of items is not important
.map($('.myItems').get(), function(el){
console.log( typeof $(el).text() )
List.push($(el).text());
}, {concurrency:1}) // Control how many items are processed at a time
// When all of the above are done, following code will be executed
.then(function(){
for (var i=0; i < List.length; i++){
// make an asynchronous call to a API
}
});
});
在这个特定的代码示例中,看起来你可能正在映射函数中进行异步调用,但是你得到了要点......
每个:https://github.com/petkaantonov/bluebird/blob/master/API.md#eachfunction-iterator---promise