已调用Node.js Async waterfall()回调

时间:2016-05-26 11:44:29

标签: javascript node.js asynchronous

我在昨天的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();
        }
      }
    });
  })
}

我错过了什么......?

1 个答案:

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