Question:
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 go into debug mode, or put an alert before the return, the resultado
returns empty. Currently, the alert exits empty but correctly returns the result (I use it to add the variable text to a div).
I have read that it can be solved by setting a Timeout, but I would like to know if there is a more elegant solution than this.
Answer:
Explanation of the problem.
The A in Ajax stands for Asynchronous; this means that the request is outside the normal flow of execution. In your code the $.ajax
, when executed, follows the return, return resultado
, and this is executed before the function or ajax request passes the value of the response to success. Therefore when you use the alert it returns empty or undefined, since the request you made has not returned.
Possible solutions that you can give to your problem:
ES2017+: Promises with async/await
The version of ECMAScript released in 2017 introduced support for asynchronous functions. With the help of async and await , you can write asynchronous code in a synchronous style. The code will still be asynchronous but it is easier to read and understand.
Async/await is based on promises, an async function will always return a promise. the Await takes the information from the promise and the result will be the value that was resolved, or else the error if it has been rejected.
Here is an example of how to create async at a high function level:
// Using 'superagent' which will return a promise.
var superagent = require('superagent')
// This is isn't declared as `async` because it already returns a promise
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);
});
}
Using Async in functions:
async function getAllBooks() {
try {
// GET a list of book IDs of the current user
var bookIDs = await superagent.get('/user/books');
// wait for 3 seconds (just for the sake of this example)
await delay();
// GET information about each book
return await superagent.get('/books/ids='+JSON.stringify(bookIDs));
} catch(error) {
// If any of the awaited promises was rejected, this catch block
// would catch the rejection reason
return null;
}
}
// Start an IIFE to use `await` at the top level
(async function(){
let books = await getAllBooks();
console.log(books);
})();
Current browser and node versions support async/await. You can also support older environments by transforming your code to ES5 with the help of regenerator (or tools that use regenerator, such as Babel).
Current versions of browsers and node support async / await. It is also supported by previous versions making use of ES5 under tools such as Babel.
Using callback functions: A callback is a function that will be called later when the Ajax request has 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 should receive a function, which jQuery will call at the end of the request if it was successful. By the way, there is another callback available to control what to do in case of errors. It is handled using the error
property; receives a callback that will be invoked in case of no success.
Use the promises:
Promises are containers for future values. When a promise receives the value if it was resolved or canceled, it will notify listeners that they want to access that return value. One of the added values is that it has more 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 custom implementation of promises implemented by jQuery; usage 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
});
Fuente – How do I return the response from an asynchronous call?