繁体   English   中英

如何在nodejs中的async.each中进行同步http调用

[英]how to make synchronous http calls within async.each in nodejs

我想向API-s发出http请求,以便为每个用户收集它的数据并插入到mongodb中。

我遇到的问题是,它正在立即执行所有请求,并且似乎卡在某处,我不知道发生了什么。

你是我使用异步库并在每次迭代中添加request()方法,我不知道这是否正确,这里是代码:

  function iterateThruAllStudents(from, to) {
    Student.find({status: 'student'})
        .populate('user')
        .exec(function (err, students) {
            if (err) {
                throw err;
            }

            async.forEach(students, function iteratee(student, callback) {
                if (student.worksnap.user != null) {
                    var options = {
                        url: 'https://api.worksnaps.com/api/projects/' + project_id + '/time_entries.xml?user_ids=' + student.worksnap.user.user_id + '&from_timestamp=' + from + '&to_timestamp=' + to,
                        headers: {
                            'Authorization': 'Basic bGhNSVJkVUFwOE1DS2loOFVyZkFyOENEZEhPSXdCdUlHdElWMHo0czo='
                        }
                    };
                    request(options, getTimeEntriesFromWorksnap);
                }
                callback(); // tell async that the iterator has completed
            }, function (err) {
                console.log('iterating done');
            });
        });
}

    function getTimeEntriesFromWorksnap(error, response, body) {
        console.log(response.statusCode);
        if (!error && response.statusCode == 200) {
            parser.parseString(body, function (err, results) {
                var json_string = JSON.stringify(results.time_entries);
                var timeEntries = JSON.parse(json_string);
                _.forEach(timeEntries, function (timeEntry) {
                    _.forEach(timeEntry, function (item) {
                        saveTimeEntry(item);
                    });
                });
            });
        }
    }

    function saveTimeEntry(item) {
        Student.findOne({
                'worksnap.user.user_id': item.user_id[0]
            })
            .populate('user')
            .exec(function (err, student) {
                if (err) {
                    throw err;
                }
                student.timeEntries.push(item);
                student.save(function (err) {
                    if (err) {
                        console.log(err);
                    } else {
                        console.log('item inserted...');
                    }
                });

            });
    }

var from = new Date(startDate).getTime() / 1000;
startDate.setDate(startDate.getDate() + 30);
var to = new Date(startDate).getTime() / 1000;
iterateThruAllStudents(from, to);

我是JavaScript的新手,特别是在处理异步时。

有帮助吗?

在你的例子中,你错过了async- iteratee(item, callback)each方法中的iteratee param。 看下面这个例子在这里

每次在iteratee函数中都需要调用callback来告诉异步继续进行处理。

each(collection, iteratee, [callback])

  • 集合 - 迭代的集合。

  • iteratee(item,callback) - 用于应用于coll中每个项目的函数。 迭代器传递一个回调(err),一旦完成就必须调用它。 如果没有发生错误,则应该在没有参数或显式null参数的情况下运行回调。 数组索引不会传递给iteratee。 如果需要索引,请使用forEachOf。

  • callback(err) - 当所有iteratee函数完成或发生错误时调用的可选回调。

如果你需要同步行为,没有probs! 除了每个集合项将同步迭代之外,还有eachSeries方法具有相同的签名。

更新:

应该实施变革:

传递async回调:

request(options, getTimeEntriesFromWorksnap(callback));

返回request回调函数所需的:

function getTimeEntriesFromWorksnap(callback) {
  return function(error, response, body) { 
    // ...       
    saveTimeEntry(item, callback);                       
    // ...
  }        
}

仅在将记录保存在数据库中后才调用callback

function saveTimeEntry(item, callback) {
  // ..
  student.save(callback);
  // ..
}

重构嵌套循环(不确定timeEntriestimeEntry是什么,所以使用适当的异步方法来迭代这些数据结构):

async.each(timeEntries, function (timeEntry, callback) {
   async.each(timeEntry, function (item, callback) {
       saveTimeEntry(item, callback);
   }, callback);
}, callback);

使用Async.eachLimit()向api发出批量请求...尝试使用iterateThruAllStudents()函数。

我在之前已经有过同样的问题

见限制的教程在这里 虽然我限制为5但你可以做任何你想做的事(10,50等)。

function iterateThruAllStudents(from, to) {
  Student.find({status: 'student'})
    .populate('user')
    .exec(function (err, students) {
      if (err) {
        throw err;
      }
      async.eachLimit(students,5,function iteratee(student, callback) {
        if (student.worksnap.user != null) {
          var options = {
            url: 'https://api.worksnaps.com/api/projects/' + project_id + '/time_entries.xml?user_ids=' + student.worksnap.user.user_id + '&from_timestamp=' + from + '&to_timestamp=' + to,
            headers: {
              'Authorization': 'Basic bGhNSVJkVUFwOE1DS2loOFVyZkFyOENEZEhPSXdCdUlHdElWMHo0czo='
            }
          };
          request(options,getTimeEntriesFromWorksnap(callback));
        }
      }, function (err) {
        console.log(err);
        console.log('iterating done');
      });
    });
}

function getTimeEntriesFromWorksnap(cb) {
  return function(error, response, body){
    console.log(response.statusCode);
    if (!error && response.statusCode == 200) {
      parser.parseString(body, function (err, results) {
        var json_string = JSON.stringify(results.time_entries);
        var timeEntries = JSON.parse(json_string);
        async.each(timeEntries,function(timeEntry,cb1){
          async.each(timeEntry,function(item,cb2){
            saveTimeEntry(item,cb2);
          },function(err){
            if(err)
              cb1(err);
            else
              cb1();
          })
        },function(err){
          if(err)
            cb(err);
          else
            cb();
        });
        //_.forEach(timeEntries, function (timeEntry) {
        //  _.forEach(timeEntry, function (item) {
        //    saveTimeEntry(item);
        //  });
        //});
      });
    }
    cb(null);
  }
}

function saveTimeEntry(item,cb2) {
  Student.findOne({
      'worksnap.user.user_id': item.user_id[0]
    })
    .populate('user')
    .exec(function (err, student) {
      if (err) {
        return cb2(err);
      }
      student.timeEntries.push(item);
      student.save(function (err) {
        if (err) {
          console.log(err);
          //return cb2(err);//Do it if you wanna throw an error.
        } else {
          console.log('item inserted...');
        }
        cb2();
      });
    });
}

var from = new Date(startDate).getTime() / 1000;
startDate.setDate(startDate.getDate() + 30);
var to = new Date(startDate).getTime() / 1000;
iterateThruAllStudents(from, to);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM