Waiting for API call to finish in Javascript before continuing

53,639

Solution 1

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);

Solution 2

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
});

Solution 3

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();
Share:
53,639
G.Thompson
Author by

G.Thompson

Updated on July 09, 2022

Comments

  • G.Thompson
    G.Thompson almost 2 years

    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);
    }
    
  • G.Thompson
    G.Thompson almost 12 years
    thanks for your time, do you have any suggestions to accomplish this?
  • Nadir Muzaffar
    Nadir Muzaffar almost 12 years
    I added an example to clarify the idea.
  • G.Thompson
    G.Thompson almost 12 years
    Thanks, this really helped me understand but what if I want to return the response to the original call? See my last edit above. I'd like to get the value and return it. So basically I have a function that calls share_share and it needs to be returned with a response.
  • epascarello
    epascarello almost 12 years
    It can't be just returned, it has to be callbacks. The return finalresponse; is the same thing you had before, just in a different way!
  • G.Thompson
    G.Thompson almost 12 years
    so I really just can't do what I want to do? Is it not possible to return an ajax/api response to a parent function?
  • epascarello
    epascarello almost 12 years
    Use if it could be done with a synchronous call, BUT you are calling another domain so it has to by asynchronous. You need to break up the logic into two steps.
  • fireball.1
    fireball.1 almost 3 years
    What if there is there is a lot of trickle down code that can't be put into a callback function ?