How to get the answer of an asynchronous call (AJAX) out of it?

26

I currently have this function:

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

Which returns the result correctly, the problem is that unless you enter debug mode, or put an alert before the return, resultado becomes empty. Currently, the alert is empty but returns the result correctly (I use it to add the text of the variable to a div).

I have read that you can fix it by setting a Timeout, but I would like to know if there is any more elegant solution than this.

    
asked by Raider 22.12.2015 в 14:03
source

4 answers

31

Explanation of the problem.

The A in Ajax means Asynchronous; this means that the request is outside the normal flow of execution. In your code the $.ajax , when executed, continues the return, return resultado , and this is executed before the ajax function or request passes the value of the response to the success. Therefore when you use the alert it returns empty or undefined, since the request you made has not returned.

Possible solutions you can give to your problem:

Use callback functions: A callback is a function that will be invoked later when the Ajax request is finished.

Example:

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

This example demonstrates that the success property must receive a function, which jQuery will invoke upon completion of the request if successful. By the way, there is another callback available to control what to do in case of errors. It is handled using the property error ; receives a callback that will be invoked in case of non-success.

Use the promises:

Promises are containers of future values. When a promise receives the value if it was resolved or canceled, it will notify listeners who want to access that returned value. One of the added values is that it has a higher code reading and in my opinion it is a much better approach. Example:

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

Use Jquery Deferred

This is a customized implementation of the promises implemented by jQuery; the use is very similar to the point explained above:

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

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

Source - How do I return the response from an asynchronous call?

    
answered by 22.12.2015 / 14:34
source
8

one of the solutions you could do is removing the Asynchronous so that you have an immediate response by placing (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;
}
    
answered by 28.06.2016 в 16:27
5

When making an Ajax call, it is executed asynchronously, that is, while the request is being made, it follows the execution of the function that you have there.

For that you have the success and error callbacks.

If you put an alert inside the Success you will be able to see the result.

$.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) {

    },
});

A serious solution to pass to your function a callback to execute it.

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

        },
    });    
 }

And you call it this way:

    devuelveButaca(1, function(resultado){ alert(resultado) });
    
answered by 22.12.2015 в 14:31
4

The value of resultado is returned empty because it is achieved through an asynchronous call (AJAX) but you are returning it synchronously (then the value has not yet been instantiated).

As you say, a possible solution would be to add a wait (or a timeout ) to ensure that the value you will get. But that can have problems: what happens if the value of waiting is not enough? Then you would still have the same problem and the value would be returned null.

This is really a misuse of AJAX. The idea is not that you return something (which would be synchronous) but that you use the values when you receive them asynchronously (in success ).

For that you could do two things:

  • Move the code from which you call the function to success . Although this option may not be very good if it is called for different reasons or from different functions to devuelveButaca() .

  • Pass as a parameter a callback function that will be called from success . In this way, you could call devuelveButaca() from different contexts and it would always work.

    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) {
    
            },
        });
    }
    
  • answered by 22.12.2015 в 14:35