Node.jsasynchronous的瀑布()callback已被调用

我在昨天的node.js上使用async模块来处理asynchronous任务的顺序。 下面的代码工作,但错误:

callback已被调用

显示约1至5次。 我不知道问题出在哪里,也许在getNewsTitles()调用forEach循环的callback不只是一次。 所以我把console.log放在这里,但是这个日志只打印一次,不pipe是否显示错误。

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

我错过了什么..?

request.get()是一个asynchronous调用。 定期循环将无法正常工作。 在上面的代码中,每调用一次request.get(),callback()就会被调用。 你需要一些你可以控制stream的东西,比如async.each(),async.eachLimit(),async.eachSeries()等,这样callback()只被调用一次。

我build议在这个场景中使用async.eachLimit()通过async.each()来限制request.get()的最大数目,这样你就不会用太多的request.get()来刷新服务器。 在下面的示例中,我使用5作为并发处理请求的最大数量,但是您可以更改服务器可以处理的值:

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