2015-01-09 44 views
1

我试图通过我有的“事件”数据库工作,并根据每个事件的位置,半径,开始时间和结束时间从Instagram API中提取照片。我在我的Node服务器上设置了下面的代码,但它不像我期望的那样运行。如何正确构造异步节点代码

我运行此代码时看到的第一件事情是为每个事件打印sending request to Instagram for [name] with min_timestamp: [timestamp]。我没有想到这一点。我预计会看到这行记录的第一个事件,然后更新一个新的时间戳,直到该事件达到其结束时间。然后事件2,遍历时间戳,等等。

我结束了每个事件反复重复的同一块照片。就好像我的代码一遍又一遍地向Instagram发出一个请求(带有初始时间戳),然后停止。

关于我的时间戳变量的注意事项:对于每个事件,我将我的minTimestamp变量设置为初始等于我的数据库中的event.start。这是在发送给Instagram的请求中使用的。 Instagram会返回20张照片给我。每张照片都有一个created_time变量。我抓取最近的created_time变量,并将我的minTimestamp变量设置为等于它(minTimestamp = images[0].created_time;),以便发送给Instagram的下一个请求(抓取接下来的20张照片)。这一直持续到MinTimestamp不再小于endTimestamp(从我的db中为该事件的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 
+0

对不起,我需要一些睡眠。你还在努力吗?如果是这样,我想再看看它,因为这是一个有趣的问题,也许我们可以打败它。你可以编辑你的问题,并详细解释min_timestamp业务是如何工作的?我无法弄清楚为什么照片增加了它,为什么它最终等于end_timestamp。 – mwarren 2015-01-10 16:03:36

+0

你是什么意思的'相同的照片块' - 只是照片从第一个事件重复或照片都是一样的? – mwarren 2015-01-10 16:09:46

+0

我没有得到真正的地方,无法测试它。太多的问题要问你。但有一点有点奇怪:这就是说while()位的主函数没有回调(),我认为这是必要的。 – mwarren 2015-01-10 17:38:51

回答

1

答案是,你缺少的回调()的同时位。

下面是一些代码来说明:

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 
    } 
); 
}, 
+0

非常感谢。看起来它应该解决这个问题。我现在在路上,但是一旦我有机会并且让你知道它是如何发生的,我会尽快实施。这看起来像我过去经常阅读Node的经典“回拨地狱”情形。一段时间之后,很难跟踪它们。 – MattDionis 2015-01-11 16:04:33

+0

是的,请让我知道,让我们希望就是这样。我已经提出了你的问题,通过它看起来很有趣。我已经删除了我的评论,其中提到了我错误的答案,也许你应该删除你的意外标识符,因为它可能会让读者感到困惑。 – mwarren 2015-01-11 16:17:08

+0

P.S.爱mobseen网站!好主意和很好的实现。 – mwarren 2015-01-11 16:31:25

0
// 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; 
       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); 
        console.log('Image processed'); 
        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 { 
        minTimestamp = images[0].created_time; 
        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; 
+0

Thankyou张贴,我明天会好好看看。 – mwarren 2015-01-12 20:22:19

+0

@mwarren,找出最后剩下的问题。增量'minTimestamp = images [0] .created_time;'需要在'callback()'之前发生。但是,'images [0] .created_time'已不再可用,因为'images'只存在于从Instagram返回的数据中。需要找到一种方法来抓取此时间戳并将其传递给minTimestamp以便在回调之前进行更新。 – MattDionis 2015-01-13 16:52:36

+1

我将更新您的答案,因为否则显示过于复杂:我们忘记了所有异步函数必须在调用回调之前完成。我已经重新命名并移动了所有的回调,以显示我认为他们应该如何。 – mwarren 2015-01-14 11:26:12