Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Waiting for API call to finish in Javascript before continuing

something I've struggled with in the past and am struggling with today is preventing an API/AJAX from continuing until you've recieved your response. currently I'm working with the Facebook API. I need to get a response from a call then return it but what's happening is that my function is returning before I ever get a response from the API call. I know why it's happening, I just can't figure out how to prevent it! Here's my code...

function makeCall(){

var finalresponse = "";
    var body = 'Test post';

      FB.api('/me/feed', 'post', { message: body }, function(response) {
        if (!response || response.error) {
         finalresponse = response.error;
        } else {
          finalresponse = 'Post ID: ' + response.id;
        }
      });
      return finalresponse;

}

// ----- EDIT

I noticed some people suggested something like this...

function makeCall(){
var finalresponse = "";
FB.api('/me/feed', 'post', { message: body }, function(response) {
        if (!response || response.error) {
         finalresponse = response.error;
         return finalresponse;
        } else {
          finalresponse = 'Post ID: ' + response.id;
          return finalresponse;
        }
      });
}

But this returns undefined

// EDIT BASED ON UPDATES

function share_share(action_id){

  var finalresponse = makeCall(action_id, process);
  return finalresponse;

}

function makeCall(action_id, callback){

var body = 'Test post';
      FB.api('/me/feed', 'post', { message: body }, function (response) {
        if (!response || response.error) {
         var finalresponse = response.error;
        } else {
          finalresponse = 'Post ID: ' + response.id;
        }
        callback(action_id, finalresponse);
      });

}
function process(action_id, finalresponse){
  console.log(finalresponse);
}
like image 555
G.Thompson Avatar asked Jun 12 '12 17:06

G.Thompson


3 Answers

The question that is asked 100 times a day and seems impossible to have one answer.

The call is asynchronous so it is impossible to do it in one step. Basic example of what you expect.

function one() {
  var a = 1;
  return a;
}
alert( one() );

What is actually happening:

function one() {
  var a;
  window.setTimeout( 
     function() {
        a = 1;
     }, 2000);
  return a;  //This line does not wait for the asynchronous call [setTimeout/ajax call] to run. It just goes!
}
alert( one() );

What you need to do is break it up into two parts.

function one( callback ) {   
   window.setTimeout( function(){  //acting like this is an Ajax call
        var a = 1;
        callback(a);
   },2000);
}
function two( response ) {
   alert(response);
}
one( two );

So in your case you would need to break up your code to handle it in two chunks.

function makeCall( callback ) {
    var body = 'Test post';
      FB.api('/me/feed', 'post', { message: body }, function (response) {
        if (!response || response.error) {
         var finalresponse = response.error;
        } else {
          finalresponse = 'Post ID: ' + response.id;
        }
        callback(finalresponse);
      });
}


function processResponse( response ) {
    console.log(response);
}
makeCall(processResponse);
like image 171
epascarello Avatar answered Nov 06 '22 20:11

epascarello


In JavaScript, there is no concept of waiting or yielding. JavaScript continues execution, without interruption, of your code to its end. It seems weird and troublesome at first, but it has its advantages.

So the idea in scenarios such as this is that the code you wish to execute after receiving your response should be put into the callback that you give to FB.api(). You'll have to break out the code after your return statement into the response callback so that it can be executed when the response is received.

This is what you might expect from JavaScript if it were like most languages (such as C++/Java):

var futureResult = SomeAsyncCall();
futureResult.Wait(); //wait untill SomeAsyncCall has returned
var data = futureResult.GetData();
//now do stuff with data

The idea in JavaScript, however, is based around callbacks when dealing with asynchrony:

SomeAsyncCall(function(result) {
    var data = result.GetData();
    //now do stuff with data
});
like image 35
Nadir Muzaffar Avatar answered Nov 06 '22 19:11

Nadir Muzaffar


You don't want to prevent from returning it as doing such a thing will block the user's browser for the duration of the request. If the request hangs for whatever reason (congestion, site maintenance, etc...) the browser will become unresponsive to any user input resulting in upset users.

Instead of doing the following:

var res = makeCall();
if(res)
{
   // do stuff
}

Do this:

function makeCall(){
    FB.api('/me/feed', 'post', { message: body }, function(response) {
        if (response && !response.error) {
            // do stuff
        }
    });
}

makeCall();
like image 40
Dave Rager Avatar answered Nov 06 '22 19:11

Dave Rager