我在昨天的node.js上使用async
模块来处理异步任务的顺序。下面的代码工作,但错误:
已经调用了回调
显示约1至5次。我不知道问题出在哪里,forEach
getNewsTitles()
循环回调可能不仅仅是一次。所以我把console.log
放在这里但是这个日志只打印了一次是否显示错误。
async.waterfall([
function(callback) {
callback();
},
function(callback) {
// When error, below log doesn't show.
console.log('getting news titles...');
getNewsTitles(arr_uri, arr_subs, function() {
// * The problem is here => "Callback was already called"
callback(null);
});
}
], function(err, result) {
if (err) return next();
else res.send(arr_subs);
});
function getNewsTitles(targets, subs, callback) {
targets.forEach(function(current, index) {
request.get({
uri: current,
encoding: null
}, function(err, response, body) {
if (!err && response.statusCode == 200) {
var $ = cheerio.load(iconv.decode(body, 'EUC-KR'));
var subject = $('.articleSubject a');
for (var i = 0; i < subject.length; i++) {
subs.push(subject[i].attribs.title);
}
if (subs.length == (targets.length - 2) * 20 + 2) {
// when error or not, below log shows one time.
console.log('doubt here too');
callback();
}
}
});
})
}
我错过了什么......?
答案 0 :(得分:1)
request.get()是一个异步调用。常规的 for 循环不起作用。在上面的代码中,每次成功的request.get()都会调用callback()。你需要一些可以控制流的东西,比如async.each(),async.eachLimit(),async.eachSeries()等,这样只能调用一次callback()。
我建议在这个场景中使用async.eachLimit()而不是async.each()来限制request.get()的最大数量,这样你就不会在服务器上刷新太多的request.get()了。时间。在下面的示例中,我使用5作为同时处理的最大请求数,但您可以更改服务器ecan处理的值:
function getNewsTitles(targets, subs, callback) {
async.eachLimit(targets, 5, function (current, eachCb) {
request.get({
uri: current,
encoding: null
}, function(err, response, body) {
if (!err && response.statusCode == 200) {
var $ = cheerio.load(iconv.decode(body, 'EUC-KR'));
var subject = $('.articleSubject a');
for (var i = 0; i < subject.length; i++) {
subs.push(subject[i].attribs.title);
}
if (subs.length == (targets.length - 2) * 20 + 2) {
// when error or not, below log shows one time.
console.log('doubt here too');
}
}
eachCb(null); // must be called for every iteration of async.eachLimit()
});
}, function (err) {
callback(null); // all items have been processed, call this callback only once
});
}