javascript - 如何正确构建异步 Node 代码

标签 javascript node.js mongodb asynchronous mongoose

我正在尝试处理我拥有的“事件”数据库,并根据每个事件的位置、半径、开始时间和结束时间从 Instagram API 中提取照片。我已经在我的 Node 服务器上设置了以下代码,但它的行为并不符合我的预期。

运行此代码时,我看到的第一件事是向 Instagram 发送 [name] 请求,并为每个事件打印 min_timestamp: [timestamp]。我没想到这一点。我本希望看到这一行记录了第一个事件,然后一遍又一遍地用新的时间戳进行更新,直到该事件到达结束时间。然后是事件 2,迭代时间戳,依此类推。

对于每个事件,我都会一遍又一遍地重复相同的照片 block 。就好像我的代码一遍又一遍地向 Instagram 发出一个请求(带有初始时间戳),然后停止。

关于我的时间戳变量的注释:对于每个事件,我将我的 minTimestamp 变量设置为最初等于数据库中的 event.start 。这在发送到 Instagram 的请求中使用。 Instagram 向我返回最多 20 张照片。每张照片都有一个created_time变量。我获取最新的created_time变量并将minTimestamp变量设置为等于它(minTimestamp = images[0].created_time;),以便发送到Instagram的下一个请求(以获取接下来的20张照片)。这一直持续到 minTimestamp 不再小于 endTimestamp(来 self 的数据库的该事件的 event.end)。

server.js 代码:

// 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, callback) {

      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(callback) {
          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;
                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, callback) {

                  //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);
                      }
                  );
                  console.log(numImages + ' images saved to db');
                  callback();
              }, function(err){
                  // if any of the file 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('All images have been processed successfully');
                  }
              });

              minTimestamp = images[0].created_time;
              console.log('min_timestamp incremented to: ' + minTimestamp);
            }
          );
        },
        function (err) {

        }
      );
      callback();
    }, function(err){
        // if any of the file 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('An event 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;                         // expose app

最佳答案

答案是您缺少 while 位的回调()。

这里有一些代码来说明:

var async = require('async');

var minTimestamp = 1;
var endTimestamp = 10;

async.whilst(
    function () { minTimestamp < endTimestamp; },
    function(callback) {
      console.log('sending request to Instagram for name with min_timestamp: ' + minTimestamp);

      minTimestamp = minTimestamp + 1;
      console.log('min_timestamp incremented to: ' + minTimestamp);
      callback();
    },
    function (err) {
        if(err){
                throw err;
        }
    }
  );

如果我在没有 callback() 的情况下运行它,我会得到以下输出:

sending request to Instagram for name with min_timestamp: 1
min_timestamp incremented to: 2

如果我放回callback(),我会得到:

sending request to Instagram for name with min_timestamp: 1
min_timestamp incremented to: 2
sending request to Instagram for name with min_timestamp: 2
min_timestamp incremented to: 3
sending request to Instagram for name with min_timestamp: 3
min_timestamp incremented to: 4
sending request to Instagram for name with min_timestamp: 4
min_timestamp incremented to: 5
sending request to Instagram for name with min_timestamp: 5
min_timestamp incremented to: 6
sending request to Instagram for name with min_timestamp: 6
min_timestamp incremented to: 7
sending request to Instagram for name with min_timestamp: 7
min_timestamp incremented to: 8
sending request to Instagram for name with min_timestamp: 8
min_timestamp incremented to: 9
sending request to Instagram for name with min_timestamp: 9
min_timestamp incremented to: 10

因此在这里放置一个回调():

      minTimestamp = images[0].created_time;
      console.log('min_timestamp incremented to: ' + minTimestamp);
      callback(); //missing callback
    }
 );
 },

关于javascript - 如何正确构建异步 Node 代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27870062/

相关文章:

javascript - 具有多个元素但单独的数组上的单击事件

javascript - 如何在php中找到与某个字符最接近的html标签?

javascript - 无法在 MongoDB 拼接服务中搜索 ObjectID

node.js - 一段时间后我可以从 mongoDB 文档中删除一个字段吗?

node.js - SEQUELIZE : belongsTo called with something that's not a subclass of Sequelize. 模型

MongoDB - sort() 数据过多,没有索引错误

javascript - 如何更改已访问链接的背景颜色

javascript - 文本区域和更改

javascript - req.body 检查是否包含特定字符

node.js - Node child_process执行自身