2015-01-09 47 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