根据最新响应在 Node 中发送同步请求

Send synchronous requests in Node based on latest response

我在我的节点服务器上使用 async 模块来循环遍历我的 mongodb 数据库中的对象,根据其中的数据触发对 Instagram API 的请求每个对象,并在每次迭代时递增 minTimestamp,直到达到 endTimestamp

除了一个大问题外,下面的代码工作得很好。如果我将 minTimestamp 增加一个硬编码值 (minTimestamp += 1000),一切运行良好。但是,当我更改那一行代码以从最近的响应 (minTimestamp = images[0].created_time) 中获取最新的 created_time 时,我的循环针对每个 'event' 运行一次然后停止。我将正确的增量 minTimestamp 记录到我的控制台,但该值似乎永远不会进入下一个循环。

// modules =================================================
var express        = require('express.io');
var app            = express();
var port           = process.env.PORT || 6060;
var io             = require('socket.io').listen(app.listen(port));
var request        = require('request');
var Instagram      = require('instagram-node-lib');
var mongoose       = require('mongoose');
var async          = require('async');
var bodyParser     = require('body-parser');
var methodOverride = require('method-override');
var db             = require('./config/db');
var Event          = require('./app/models/event');

// configuration ===========================================
mongoose.connect(db.url); // connect to our mongoDB database

// get all data/stuff of the body (POST) parameters
app.use(bodyParser.json()); // parse application/json 
app.use(bodyParser.json({ type: 'application/vnd.api+json' })); //  parse        application/vnd.api+json as json
app.use(bodyParser.urlencoded({ extended: true })); // parse application/x-www-form- urlencoded

app.use(methodOverride('X-HTTP-Method-Override')); // override with the X-HTTP-Method- Override  header in the request. simulate DELETE/PUT
app.use(express.static(__dirname + '/public')); // set the static files location  /public/img  will be /img for users

var baseUrl = 'https://api.instagram.com/v1/media/search?lat=';
var clientId = CLIENT-ID;

Event.find({}, function(err, events) {

  async.eachSeries(events, function(event, seriesCallback) {

  var name = event.event;
  var latitude = event.latitude;
  var longitude = event.longitude;
  var distance = event.radius;
  var minTimestamp = Math.floor(new Date(event.start).getTime()/1000);
  var endTimestamp = Math.floor(new Date(event.end).getTime()/1000);

  async.whilst(
    function () { return minTimestamp < Math.floor(Date.now() / 1000) && minTimestamp <  endTimestamp; },
      function(requestFinishedCallback) {
        console.log('sending request to Instagram for ' + name + ' with min_timestamp: ' + minTimestamp);
        request(baseUrl + latitude + '&lng=' + longitude + '&distance=' + distance + '&min_timestamp=' + minTimestamp + '&client_id=' + clientId,
          function (error, response, body) {
            if (error) { 
              console.log('error');
              return;
            }

            //JSON object with all the info about the image
            var imageJson = JSON.parse(body);
            var images = imageJson.data;
            var numImages = images.length;
            if (numImages > 0) {
              console.log(numImages + ' images returned with starting time ' + images[(numImages - 1)].created_time + ' and ending time ' + images[0].created_time);
            }

            async.eachSeries(images, function(image, imageFinishedCallback) {

              //Save the new object to DB
              Event.findOneAndUpdate( { $and: [{latitude: latitude}, {radius: distance}] }, { $push: {'photos':
                { img: image.images.standard_resolution.url,
                  link: image.link,
                  username: image.user.username,
                  profile: image.user.profile_picture,
                  text: image.caption ? image.caption.text : '',
                  longitude: image.location.longitude,
                  latitude: image.location.latitude
                }}},
                { safe: true, upsert: false },
                function(err, model) {
                  console.log(err);  
                }
              );
              imageFinishedCallback();
            }, function(err){
                 // if any of the image processing produced an error, err would equal that error
                 if( err ) {
                   // One of the iterations produced an error.
                   // All processing will now stop.
                   console.log('Images failed to process');
                 } else {
                   console.log('Images processed');
                 }
               });
              // this works
              minTimestamp += 1000;
              // this does not
              // minTimestamp = images[0].created_time;
              if (numImages > 0) {
                console.log(numImages + 'images have been processed successfully and min_timestamp has been incremented to: ' + minTimestamp);
              }
            requestFinishedCallback();
          }
        );
         }, function(err){
               // if any of the image processing produced an error, err would equal that error
               if( err ) {
                 // One of the iterations produced an error.
                 // All processing will now stop.
                 console.log('Event failed to process');
               } else {
                 console.log(name + ' has been fully processed successfully with final min_timestamp of: ' + minTimestamp);
               }
          }
);
        seriesCallback();
         }, function(err){
                // if any of the image processing produced an error, err would equal that error
                if( err ) {
                  // One of the iterations produced an error.
                  // All processing will now stop.
                  console.log('Something failed to process');
                } else {
                  console.log('All events have been processed successfully');
                }
            }
);
});

// routes ==================================================
require('./app/routes')(app); // configure our routes

// start app ===============================================
console.log('Magic happens on port ' + port);           // shoutout to  the user
exports = module.exports = app;

如果你有一个 git 回购协议我可以看看,我可以更好地调试它,但是......也就是说,我看到两个明显的问题:

  1. 尽管您正在执行 async.eachSeries,但您并未等待完成 findOneAndUpdate 调用。

你的例子:

Event.findOneAndUpdate( {}, {},
    function(err, model) {
        console.log(err);  
    }
);
imageFinishedCallback();

应该变成这样:

Event.findOneAndUpdate( {}, {},
    function(err, model) {
        console.log(err);  
        imageFinishedCallback();
    }
);
  1. 与第一个问题类似,但有 async.whilst 回调。您正在调用 async.eachSeries,但随后立即进入下一个循环。

您的代码:

function (error, response, body) {
    // ...
    async.eachSeries(images, function(image, imageFinishedCallback) {/* ... */},
    function(err){
        // ...
    });

    // this works
    minTimestamp += 1000;
    // this does not
    // minTimestamp = images[0].created_time;
    if (numImages > 0) {
        console.log(numImages + 'images have been processed successfully and min_timestamp has been incremented to: ' + minTimestamp);
    }
    requestFinishedCallback();
}

应改为:

function (error, response, body) {
    // ...
    async.eachSeries(images, function(image, imageFinishedCallback) {/* ... */},
    function(err){
        // ...
        console.log(numImages + 'images have been processed successfully and min_timestamp has been incremented to: ' + minTimestamp);
        minTimestamp = images[0].created_time;
        requestFinishedCallback();
    });
}

如果你有一个 github 回购到 post 我可以进一步调试,但是......看起来问题是因为没有等待异步函数完成。