¿Cómo obtener la respuesta de una llamada asíncrona (AJAX) fuera de ella? – javascript jquery asincrónico

Pregunta:


Actualmente tengo esta función:

function devuelveButaca(posicion){
    var array = posicion.split('_');
    var row = array[0];
    var column = array[1];
    var planta = $('#plantaField').val();
    var resultado = "";
    $.ajax({
        type : 'GET',
        url : 'site/numButaca',
        data : {
            planta : planta,
            column : column,
            row : row
        },
        success : function(data) {
            if(data == 'undefined' || data == ''){
                resultado = column;

            }else{
                resultado = data;
            }
        },
        error : function(request, status, error) {

        },
    });
    alert(resultado);
    return resultado;
}

La cual devuelve el resultado correctamente, el problema es que a menos que entre en modo debug, o ponga un alert antes del return, resultado vuelve vacío. Actualmente, el alert sale vacío pero devuelve correctamente el resultado (la uso para agregar el texto de la variable a un div).

He leído que se puede solucionar poniendo un Timeout, pero me gustaría saber si hay alguna solución mas elegante que esta.

Preguntado por: Raider

Comunidad

Explicación del problema.

La A en Ajax significa Asíncrono; esto quiere decir que la petición está fuera del flujo normal de ejecución. En tu código el $.ajax, al ejecutarse, continúa el return, return resultado, y esta es ejecutada antes de que la función o petición ajax pase el valor de la respuesta al success. Por ende cuando usas el alert te devuelve vacío o undefined, ya que no ha vuelto la petición que hiciste.

Posibles soluciones que le puedes dar a tu problema:

Usar funciones callbacks:
Un callback es una función que será invocada más tarde cuando la petición Ajax haya finalizado.

Ejemplo:

function hacerPeticionAjax(url, callback) { // callback es solo el nombre de la variable
    $.ajax(url, {
        // ...
        success: callback,
        // ...
    });
}

function alRecibirAnimales(animales) {
  // animales contendrá la respuesta al ajax
} 

hacerPeticionAjax('/api/animales', alRecibirAnimales);

Este ejemplo demuestra que la propiedad success debe recibir una función, que jQuery invocará al finalizar la solicitud si tuvo éxito. Por cierto, hay otro callback disponible para controlar qué hacer en caso de errores. Se maneja utilizando la propiedad error; recibe un callback que sera invocado en caso de no éxito.

Usar las promesas:

Las promesas son contenedores de valores futuros. Cuando una promesa recibe el valor si fue resuelta o cancelada, él notificará a los escuchas que quieren acceder a ese valor retornado. Uno de los valores agregados es que tiene mayor lectura de código y a mi parecer es un enfoque mucho mejor. Ejemplo:

function delay() {
  // `delay` returns a promise
  return new Promise(function(resolve, reject) {
    // Only `delay` is able to resolve or reject the promise
    setTimeout(function() {
      resolve(42); // After 3 seconds, resolve the promise with value 42
    }, 3000);
  });
}

delay().then(function(v) { // `delay` returns a promise
  console.log(v); // Log the value once it is resolved
}).catch(function(v) {
  // Or do something else if it is rejected 
  // (it would not happen in this example, since `reject` is not called).
});

Usar Jquery Deferred

Esta es una implementación customizada de las promesas implementada por jQuery; el uso es muy similar al punto explicado anteriormente:

function ajax() {
    return $.ajax(...);
}

ajax().done(function(result) {
    // Code depending on result
}).fail(function() {
    // An error occurred
});

Fuente – How do I return the response from an asynchronous call?

una de las soluciones que podrías hacer es quitando el Asincrono para que tengas una respuesta inmediata colocando(async: false).

function devuelveButaca(posicion){
var array = posicion.split('_');
var row = array[0];
var column = array[1];
var planta = $('#plantaField').val();
var resultado = "";
$.ajax({
    async: false,
    type : 'GET',
    url : 'site/numButaca',
    data : {
        planta : planta,
        column : column,
        row : row
    },
    success : function(data) {
        if(data == 'undefined' || data == ''){
            resultado = column;

        }else{
            resultado = data;
        }
    },
    error : function(request, status, error) {

    },
});
alert(resultado);
return resultado;
}

Al hacer una llamada Ajax este se ejecuta de manera asíncrona, es decir mientras se hace la petición sigue la ejecución de la función que tenes ahí.

Para eso tenes los callback de success y error.

Si pones un alert dentro del Success vas a poder ver el resultado.

$.ajax({
    type : 'GET',
    url : 'site/numButaca',
    data : {
        planta : planta,
        column : column,
        row : row
    },
    success : function(data) {
        if(data == 'undefined' || data == ''){
            resultado = column;

        }else{
            resultado = data;
        }
        alert(resultado);
    },
    error : function(request, status, error) {

    },
});

Una solución seria pasarle a tu funcion un callback para ejecutarlo.

function devuelveButaca(posicion, callback){
    var array = posicion.split('_');
    var row = array[0];
    var column = array[1];
    var planta = $('#plantaField').val();
    var resultado = "";
    $.ajax({
        type : 'GET',
        url : 'site/numButaca',
        data : {
            planta : planta,
            column : column,
            row : row
        },
        success : function(data) {
            if(data == 'undefined' || data == ''){
               resultado = column;
            }else{
               resultado = data;
            }
            if(callback)
                callback(resultado);
        },
        error : function(request, status, error) {

        },
    });    
 }

Y lo llamas de la siguiente forma:

    devuelveButaca(1, function(resultado){ alert(resultado) });

El valor de resultado se devuelve vacío porque se consigue a través de una llamada asíncrona (AJAX) pero estás devolviéndolo de manera síncrona (entonces el valor aún no se ha instanciado).

Como dices, una posible solución sería añadir una espera (o un timeout) para asegurarte que el valor lo vas a obtener. Pero eso puede tener problemas: ¿qué pasa si el valor de la espera no es suficiente? Entonces seguirías teniendo el mismo problema y el valor se devolvería nulo.

Realmente esto es un uso incorrecto de AJAX. La idea no es que devuelvas algo (que sería síncrono) sino que utilices los valores cuando los recibas de manera asíncrona (en el success).

Para eso podrías hacer dos cosas:

  1. Mover el código desde el que llamas a la función al success. Aunque esta opción puede no ser muy buena si se llama por diferentes motivos o desde diferentes funciones a devuelveButaca().

  2. Pasa como parámetro una función de callback que se llamará desde el success. De este modo, podrías llamar a devuelveButaca() desde diferentes contextos y siempre funcionaría.

    function devuelveButaca(posicion, callback){
        var array = posicion.split('_');
        var row = array[0];
        var column = array[1];
        var planta = $('#plantaField').val();
        var resultado = "";
        $.ajax({
            type : 'GET',
            url : 'site/numButaca',
            data : {
                planta : planta,
                column : column,
                row : row
            },
            success : function(data) {
                if(data == 'undefined' || data == ''){
                    resultado = column;
    
                }else{
                    resultado = data;
                }
    
                callback(resultado);
            },
            error : function(request, status, error) {
    
            },
        });
    }
    

Fuente

Related Posts:

Evitar múltiples toggle con misma clase – javascript
Pregunta: Para un evento toggle con puro javascript lo desarrollo de la siguiente forma: Javascript // Esta clase lo expande. const expandButton = document.querySelector('.expand-button'); expandButton.addEventListener('click', ()=> { ...
Validación de datos nulos en una función – javascript
Pregunta: Tengo la siguiente función pero al momento validar todos mis datos me los registra todos a excepción del los "containers" que son grids y ...
Como poner una imagen de fondo a pantalla completa – javascript jquery html5
Pregunta: Como puedo hacer que la imagen abarque todo el tamaño de la pantalla. Se que de las propiedad min-width y min-heigth pero ellas no ...
Error de: Uncaught TypeError: url.indexOf is not a function por Jquery – javascript jquery
Pregunta: En el navegador, reviso en inspeccionar elemento, y me sale el siguiente error: Uncaught TypeError: url.indexOf is not a function Me imagino que es ...
Actualizar información con ajax php mysql – php jquery mysql
Pregunta: Tengo esta simple consulta que lo que simplemente me muestra las visitas de la web, pero quisiera que fuera automático con ajax ya que ...
Como validar array checkbox – javascript php jquery
Pregunta: Que tal buen dia, alguien me podria decir como se puede hacer para que cuando presione el boton "BAJAR DATOS" si este esta vacio ...
Uso de js y c# en unity. ¿Igual rendimiento? – javascript c# unity3d
Pregunta: Estoy comenzando con unity . Y veo que se pueden usar c# y js para programar. Mi pregunta es si tanto c# como js ...
Como cambiar una propiedad html dependiendo del valor de un perfil recogido de clase java – javascript jquery html
Pregunta: Tengo una caja de texto en la que me gustaría poder escribir o no dependiendo del perfil que utilice la aplicación. Esta caja de ...
Agregar marcador especifico a una localización Google Maps – javascript google-maps
Pregunta: ¿Cómo podría añadir un marcador personalizado en Google maps? Actualmente el código que tengo es el siguiente: var locations = [ ['Bondi Beach', -33.890542, ...
Usar variable en otra función con javascript – javascript html app
Pregunta: Primero que todo voy a dejar un enlace donde pueden ver el ejemplo funcionando de manera completa. Enlace a la pagina AQUI El valor elegido en ...
Ocultar y Mostrar con Mapa de Google – javascript c# asp.net
Pregunta: Tengo un div en mi página ASP.NET que contiene un Mapa de Google, y necesito mostrarlo y ocultarlo pero no me funciona. Este es el ...
Copiar valor a un input que esta dentro de un footer de un datatable – javascript jquery datatables
Pregunta: Estoy usando los DataTables de jQuery y me estoy encontrando con el siguiente problema: cuando pulso en un botón necesito pasarle un valor con ...
¿Cómo rellenar cada circulo al pasar el mouse encima? – javascript jquery html
Pregunta: ¡Hola! Estoy practicando jQuery, y me gustaría poder hacer como un ranking. A lo que quiero llegar es que cada vez que el mouse ...
convertir array a Map en javascript – javascript map nodejs
Pregunta: quiero convertir un arreglo a Map(), en este console "console.log(arrayParaMap);" sale undefined el ejemplo que uso es este //example {a:1,a:2,a:1,b:1,b:5,b:6} el map que prentendo obtener es ...
como iterar un objeto en nodejs – javascript nodejs
Pregunta: Hice esta función: const obj = ; const objMapped = obj.reduce((acc, item) => { ...

Add a Comment

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *