I am trying to use the node-facebook-sdk to make FB graph API calls using Node.JS
I want to get feed data from all of a users friends. FB graph API only allows 50 friends per batch request, so I am making a series of batch FB.api() calls.
I am trying to store the FB.api() calls in an array, then using jQuery when() to call the deferred functions.
1) the function I pass to the .done() function is executed prematurely. 2) the console.log(feed) is executed after .done(), which to my knowledge shouldn't happen.
$ = require('jQuery');
//maximum batch size request is 50. use 2-D array to store in buckets of 50 friends each.
var numFriends = friends.data.length;
var batch = [];
var deferred = [];//array to hold all the requests
var feed_dump = [];//where we collect all the feed data
//initialize a bucket for each set of 50 friends
for (var i = 0, ii = numFriends / 50; i < ii; i++) {batch.push([]);}
//put corresponding requests in in buckets.
for (var i = 0; i < numFriends; i++) {
batch[Math.floor(i/50)].push({ method: 'get', relative_url: friends.data[i].id + '/feed?since=' + '-1 month'});//not sure if the date format will work user.last_updated
}
//make the multiquery request for each bucket
for (var i in batch) {
var bucket = batch[i];
//nested FB api call
deferred.push(FB.api('', 'post', {'batch' : bucket}, function(res){//res = array 50 friend feeds
if (!res || res.error) {
console.log(!res ? 'error occurred' : res.error); return;
}
for (var j in res) {
var feed = JSON.parse(res[j].body);
console.log(feed);
feed_dump.push(feed);//feed for each friend appeneded to dump
}
}));
}
console.log('this should show up before graph api requests are made.');
//jQuery when() function.
$.when.apply(null, deferred).done(function() {
console.log('hopefully feed_dump has been updated...');
PySocket.emit('update_user_graph',JSON.stringify(feed_dump));
});
How can I defer the batch FB.api() requests properly? Also, if someone can think of a better way to do this, please let me know; I am not that experienced with async javascript.
I guess a simpler form of my question is : how can I wait for multiple callback functions to finish?
Thanks a bunch.
EDIT : Encapsulated callback count decrement : http://jsfiddle.net/3L9zc/32/
function BatchAPICalls(){
var calls = [];
var self = this;
self.push = function(){
var args = [];
for(var i = 1; i < arguments.length - 1; i++)
args.push(arguments[i]);
calls.push({
fn: arguments[0],
callback: arguments[arguments.length - 1],
args: args
});
};
self.start = function(callback){
var callbacksLeft = calls.length;
function batchCallback(){
callbacksLeft--;
if(callbacksLeft == 0)
callback();
}
for(var i = 0; i < calls.length; i++){
var call = calls[i];
var batchItemCallback = function(){
call.callback.apply(this, arguments);
batchCallback();
};
call.fn.apply(this, call.args.concat([batchItemCallback]));
}
};
}
var numFriends = friends.data.length;
var batch = [];
var feed_dump = [];
for (var i = 0, ii = numFriends / 50; i < ii; i++) {
batch.push([]);
}
for (var i = 0; i < numFriends; i++) {
batch[Math.floor(i/50)].push({
method: 'get',
relative_url: friends.data[i].id + '/feed?since=' + '-1 month'
});
}
function done() {
console.log('hopefully feed_dump has been updated...');
PySocket.emit('update_user_graph',JSON.stringify(feed_dump));
}
var batchCalls = new BatchAPICalls();
for (var i in batch) {
var bucket = batch[i];
batchCalls.push(FB.api, 'call #' + i, 'post', {'batch' : bucket}, function(res){
if (!res || res.error) {
console.log(!res ? 'error occurred' : res.error); return;
}
for (var j in res) {
var feed = JSON.parse(res[j].body);
console.log(feed);
feed_dump.push(feed);//feed for each friend appeneded to dump
}
});
}
console.log('this should show up before graph api requests are made.');
batchCalls.start(done);