Esperando a que finalice la llamada a la API en Javascript antes de continuar

algo con lo que he luchado en el pasado y con lo que estoy luchando hoy es evitar que una API/AJAX continúe hasta que haya recibido su respuesta. actualmente estoy trabajando con la API de Facebook. Necesito obtener una respuesta de una llamada y luego devolverla, pero lo que sucede es que mi función regresa antes de que reciba una respuesta de la llamada a la API. ¡Sé por qué sucede, pero no sé cómo prevenirlo! Aquí está mi código...

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;

}

// ----- EDITAR

Noté que algunas personas sugirieron algo como esto...

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

Pero esto devuelve indefinido

// EDITAR BASADO EN ACTUALIZACIONES

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

preguntado el 12 de junio de 12 a las 18:06

Yo creo porque tu return finalresponse; está fuera de la llamada a la API. -

su devolución se ejecutará antes de que se complete FB.api -

el código que proporcionó en su edición es incorrecto. Devolver finalResponse en su devolución de llamada se devolverá a la persona que llama de su devolución de llamada de respuesta. La razón por la que se devuelve undefined a la persona que llama para makeCall() es porque make call no devuelve nada. -

3 Respuestas

La pregunta que se hace 100 veces al día y parece imposible tener una respuesta.

La llamada es asíncrona por lo que es imposible realizarla en un solo paso. Ejemplo básico de lo que esperas.

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

Qué está pasando realmente:

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

Lo que tienes que hacer es dividirlo en dos partes.

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

Entonces, en su caso, necesitaría dividir su código para manejarlo en dos partes.

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

Respondido el 12 de junio de 12 a las 18:06

Gracias, esto realmente me ayudó a entender, pero ¿qué pasa si quiero devolver la respuesta a la llamada original? Vea mi última edición arriba. Me gustaría obtener el valor y devolverlo. Básicamente, tengo una función que llama a share_share y debe devolverse con una respuesta. - G.Thompson

No se puede simplemente devolver, tiene que ser una devolución de llamada. El return finalresponse; es lo mismo que tenías antes, ¡solo que de una manera diferente! - epascarello

entonces realmente no puedo hacer lo que quiero hacer? ¿No es posible devolver una respuesta ajax/api a una función principal? - G.Thompson

Use si se puede hacer con una llamada síncrona, PERO está llamando a otro dominio, por lo que tiene que ser asíncrono. Necesita dividir la lógica en dos pasos. - epascarello

En JavaScript, no existe el concepto de esperar o ceder. JavaScript continúa la ejecución, sin interrupción, de su código hasta el final. Parece extraño y problemático al principio, pero tiene sus ventajas.

Entonces, la idea en escenarios como este es que el código que desea ejecutar después de recibir su respuesta debe colocarse en la devolución de llamada que le da a FB.api(). Tendrá que desglosar el código después de su declaración de devolución en la devolución de llamada de respuesta para que pueda ejecutarse cuando se reciba la respuesta.

Esto es lo que podrías esperar de JavaScript si fuera como la mayoría de los lenguajes (como C++/Java):

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

La idea en JavaScript, sin embargo, se basa en devoluciones de llamada cuando se trata de asincronía:

SomeAsyncCall(function(result) {
    var data = result.GetData();
    //now do stuff with data
});

Respondido el 12 de junio de 12 a las 18:06

gracias por su tiempo, ¿tiene alguna sugerencia para lograr esto? - G.Thompson

Agregué un ejemplo para aclarar la idea. - Nadir Muzaffar

¿Qué pasa si hay mucho código filtrado que no se puede poner en una función de devolución de llamada? - bola de fuego 1

No desea evitar que se devuelva, ya que al hacerlo se bloqueará el navegador del usuario mientras dure la solicitud. Si la solicitud se bloquea por cualquier motivo (congestión, mantenimiento del sitio, etc.), el navegador no responderá a ninguna entrada del usuario, lo que provocará malestar en los usuarios.

En lugar de hacer lo siguiente:

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

Hacer esto:

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

makeCall();

Respondido el 12 de junio de 12 a las 18:06

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.