¿Cómo devuelvo la respuesta de una llamada asíncrona?

Tengo una función foo que hace una solicitud de Ajax. ¿Cómo puedo devolver la respuesta de foo ?

Traté de devolver el valor de la callback de success , así como asignar la respuesta a una variable local dentro de la función y devolver esa, pero ninguna de esas formas realmente devuelve la respuesta.

 function foo() { var result; $.ajax({ url: '...', success: function(response) { result = response; // return response; // <- I tried that one as well } }); return result; } var result = foo(); // It always ends up being `undefined`. 

-> Para una explicación más general del comportamiento asíncrono con diferentes ejemplos, consulte ¿Por qué mi variable permanece inalterada después de modificarla dentro de una función? – Referencia de código asíncrono

-> Si ya comprende el problema, salte a las posibles soluciones a continuación.

El problema

La A en Ajax significa asincrónico . Eso significa que el envío de la solicitud (o más bien la recepción de la respuesta) se saca del flujo de ejecución normal. En su ejemplo, $.ajax regresa inmediatamente y la siguiente statement, return result; , se ejecuta antes de la función que pasó como llamada de success incluso se llamó.

Aquí hay una analogía que con suerte hace la diferencia entre el flujo de flujo sincrónico y asíncrono:

Sincrónico

Imagine que hace una llamada telefónica a un amigo y le pide que busque algo por usted. Aunque puede llevar un tiempo, esperas por teléfono y miras fijamente al espacio, hasta que tu amigo te dé la respuesta que necesitas.

Lo mismo ocurre cuando realiza una llamada a función que contiene el código “normal”:

 function findItem() { var item; while(item_not_found) { // search } return item; } var item = findItem(); // Do something with item doSomethingElse(); 

Aunque findItem puede tardar mucho tiempo en ejecutarse, cualquier código que venga después de var item = findItem(); tiene que esperar hasta que la función devuelva el resultado.

Asincrónico

Llamas a tu amigo nuevamente por la misma razón. Pero esta vez le dices que tienes prisa y que debe llamarte de nuevo a tu teléfono móvil. Cuelga, sal de la casa y haz lo que planeas hacer. Una vez que su amigo lo devuelve, está tratando con la información que le dio.

Eso es exactamente lo que sucede cuando haces una solicitud de Ajax.

 findItem(function(item) { // Do something with item }); doSomethingElse(); 

En lugar de esperar la respuesta, la ejecución continúa inmediatamente y se ejecuta la instrucción después de la llamada Ajax. Para obtener la respuesta eventualmente, usted proporciona una función para ser llamado una vez que se recibió la respuesta, una callback (¿notará algo ?, ¿ volverá a llamar ?). Cualquier instrucción que venga después de esa llamada se ejecuta antes de llamar a la callback.


Solución (es)

¡Abraza la naturaleza asíncrona de JavaScript! Mientras que ciertas operaciones asincrónicas proporcionan contrapartes sincrónicas (también lo hace “Ajax”), generalmente se desaconseja su uso, especialmente en un contexto de navegador.

¿Por qué es malo, preguntas?

JavaScript se ejecuta en el subproceso de interfaz de usuario del navegador y cualquier proceso de ejecución larga bloqueará la interfaz de usuario, por lo que no responde. Además, hay un límite superior en el tiempo de ejecución para JavaScript y el navegador le preguntará al usuario si continuará la ejecución o no.

Todo esto es una experiencia de usuario realmente mala. El usuario no podrá decir si todo está funcionando bien o no. Además, el efecto será peor para los usuarios con una conexión lenta.

A continuación, veremos tres soluciones diferentes que se están construyendo una encima de la otra:

  • Promesas con async/await await (ES2017 +, disponible en navegadores más antiguos si usa un transpiler o regenerador)
  • Devolución de llamada (popular en el nodo)
  • Promesas con then() (ES2015 +, disponible en navegadores antiguos si usa una de las muchas bibliotecas de promesa)

Los tres están disponibles en los navegadores actuales y el nodo 7+.


ES2017 +: Promesas con async/await

La nueva versión de ECMAScript lanzada en 2017 introdujo el soporte de nivel de syntax para funciones asincrónicas. Con la ayuda de async y await , puede escribir asincrónicamente en un “estilo síncrono”. Sin embargo, no se equivoque: el código sigue siendo asincrónico, pero es más fácil de leer / comprender.

async/await basa en las promesas: una función async siempre devuelve una promesa. await “desenrollar” una promesa y dar como resultado el valor con el que se resolvió la promesa o arrojar un error si la promesa fue rechazada.

Importante: solo puede usar await dentro de una función async . Eso significa que en el nivel más alto, aún tienes que trabajar directamente con la promesa.

Puede leer más sobre async y await en MDN.

Aquí hay un ejemplo que se basa en la demora anterior:

 // 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); }); } 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; } } // Async functions always return a promise getAllBooks() .then(function(books) { console.log(books); }); 

Las versiones más recientes de navegador y nodo admiten async/await . También puede admitir entornos más antiguos transformando su código a ES5 con la ayuda de regenerator (o herramientas que usan regenerator, como Babel ).


Deja que las funciones acepten devoluciones de llamada

Una callback es simplemente una función pasada a otra función. Esa otra función puede llamar a la función pasada cuando esté lista. En el contexto de un proceso asíncrono, se llamará a la callback siempre que se realice el proceso asincrónico. Por lo general, el resultado se pasa a la callback.

En el ejemplo de la pregunta, puede hacer que foo acepte una callback y usarla como callback success . Así que esto

 var result = foo(); // Code that depends on 'result' 

se convierte

 foo(function(result) { // Code that depends on 'result' }); 

Aquí definimos la función “en línea” pero puede pasar cualquier referencia de función:

 function myCallback(result) { // Code that depends on 'result' } foo(myCallback); 

foo sí se define de la siguiente manera:

 function foo(callback) { $.ajax({ // ... success: callback }); } 

callback se referirá a la función que pasamos a foo cuando la llamamos y simplemente la pasamos al success . Es decir, una vez que la solicitud de Ajax sea exitosa, $.ajax llamará a la callback y pasará la respuesta a la callback (que se puede consultar con el result , ya que así es como definimos la callback).

También puede procesar la respuesta antes de pasarla a la callback:

 function foo(callback) { $.ajax({ // ... success: function(response) { // For example, filter the response callback(filtered_response); } }); } 

Es más fácil escribir código utilizando devoluciones de llamada de lo que parece. Después de todo, JavaScript en el navegador está fuertemente orientado a eventos (eventos DOM). Recibir la respuesta de Ajax no es más que un evento.
Pueden surgir dificultades cuando tiene que trabajar con código de terceros, pero la mayoría de los problemas pueden resolverse simplemente pensando en el flujo de la aplicación.


ES2015 +: Promesas con then ()

The Promise API es una nueva característica de ECMAScript 6 (ES2015), pero ya tiene un buen soporte para el navegador . También hay muchas bibliotecas que implementan la API Promises estándar y proporcionan métodos adicionales para facilitar el uso y la composición de funciones asíncronas (por ejemplo, bluebird ).

Las promesas son contenedores para valores futuros . Cuando la promesa recibe el valor (se resuelve ) o cuando se cancela ( rechaza ), notifica a todos sus “oyentes” que desean acceder a este valor.

La ventaja sobre las devoluciones de llamada simples es que le permiten desacoplar su código y son más fáciles de componer.

Aquí hay un ejemplo simple de usar una promesa:

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

Aplicado a nuestra llamada Ajax podríamos usar promesas como esta:

 function ajax(url) { return new Promise(function(resolve, reject) { var xhr = new XMLHttpRequest(); xhr.onload = function() { resolve(this.responseText); }; xhr.onerror = reject; xhr.open('GET', url); xhr.send(); }); } ajax("/echo/json") .then(function(result) { // Code depending on result }) .catch(function() { // An error occurred }); 

Describir todas las ventajas que prometen ofrecer está más allá del scope de esta respuesta, pero si escribe un código nuevo, debe considerarlo seriamente. Proporcionan una gran abstracción y separación de su código.

Más información sobre las promesas: HTML5 rocks – JavaScript Promises

Nota al margen: objetos diferidos de jQuery

Los objetos diferidos son la implementación personalizada de promesas de jQuery (antes de que la API Promesa fuera estandarizada). Se comportan casi como las promesas, pero exponen una API ligeramente diferente.

Todos los métodos Ajax de jQuery ya devuelven un “objeto diferido” (en realidad una promesa de un objeto diferido) que puede devolver desde su función:

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

Nota al margen: ganas de promesa

Tenga en cuenta que las promesas y los objetos diferidos son solo contenedores para un valor futuro, no son el valor en sí mismo. Por ejemplo, supongamos que tiene lo siguiente:

 function checkPassword() { return $.ajax({ url: '/password', data: { username: $('#username').val(), password: $('#password').val() }, type: 'POST', dataType: 'json' }); } if (checkPassword()) { // Tell the user they're logged in } 

Este código no entiende los problemas de asincronía anteriores. Específicamente, $.ajax() no congela el código mientras revisa la página ‘/ contraseña’ en su servidor; envía una solicitud al servidor y, mientras espera, devuelve inmediatamente un objeto jQuery Ajax diferido, no la respuesta de el servidor. Eso significa que la sentencia if siempre obtendrá este objeto Diferido, lo tratará como true y procederá como si el usuario estuviera conectado. No es bueno.

Pero la solución es fácil:

 checkPassword() .done(function(r) { if (r) { // Tell the user they're logged in } else { // Tell the user their password was bad } }) .fail(function(x) { // Tell the user something bad happened }); 

No recomendado: llamadas síncronas “Ajax”

Como mencioné, algunas (!) Operaciones asincrónicas tienen contrapartes síncronas. No defiendo su uso, pero para mayor completitud, así es como realizaría una llamada sincrónica:

Sin jQuery

Si usa directamente un objeto XMLHTTPRequest , pase false como tercer argumento a .open .

jQuery

Si usa jQuery , puede establecer la opción async en false . Tenga en cuenta que esta opción está en desuso desde jQuery 1.8. A continuación, puede utilizar una callback success o acceder a la propiedad responseText del objeto jqXHR :

 function foo() { var jqXHR = $.ajax({ //... async: false }); return jqXHR.responseText; } 

Si usa cualquier otro método jQuery Ajax, como $.get , $.getJSON , etc., debe cambiarlo a $.ajax (ya que solo puede pasar los parámetros de configuración a $.ajax ).

¡Aviso! No es posible realizar una solicitud JSONP sincrónica. JSONP, por su propia naturaleza, siempre es asincrónico (una razón más para no considerar esta opción).

Si no está usando jQuery en su código, esta respuesta es para usted

Tu código debe ser algo así como esto:

 function foo() { var httpRequest = new XMLHttpRequest(); httpRequest.open('GET', "/echo/json"); httpRequest.send(); return httpRequest.responseText; } var result = foo(); // always ends up being 'undefined' 

Félix Kling hizo un buen trabajo al escribir una respuesta para las personas que usan jQuery para AJAX, he decidido ofrecer una alternativa para las personas que no lo son.

( Nota: para aquellos que usan la nueva API fetch , Angular o promesas he agregado otra respuesta a continuación )


A lo que te enfrentas

Este es un breve resumen de “Explicación del problema” de la otra respuesta, si no está seguro después de leer esto, lea eso.

La A en AJAX significa asincrónico . Eso significa que el envío de la solicitud (o más bien la recepción de la respuesta) se saca del flujo de ejecución normal. En su ejemplo, .send devuelve inmediatamente y la siguiente statement, return result; , se ejecuta antes de la función que pasó como llamada de success incluso se llamó.

Esto significa que cuando regresa, el oyente que ha definido aún no se ejecutó, lo que significa que el valor que está devolviendo no se ha definido.

Aquí hay una analogía simple

 function getFive(){ var a; setTimeout(function(){ a=5; },10); return a; } 

(Violín)

El valor de a retorno undefined está undefined ya que la parte a=5 aún no se ha ejecutado. AJAX actúa así, está devolviendo el valor antes de que el servidor tenga la oportunidad de decirle a su navegador cuál es ese valor.

Una posible solución a este problema es codificar de forma activa , diciéndole a su progtwig qué hacer cuando se complete el cálculo.

 function onComplete(a){ // When the code completes, do this alert(a); } function getFive(whenDone){ var a; setTimeout(function(){ a=5; whenDone(a); },10); } 

Esto se llama CPS . Básicamente, le estamos getFive una acción para que se realice cuando se complete; le estamos diciendo a nuestro código cómo reactjsr cuando se completa un evento (como nuestra llamada AJAX o, en este caso, el tiempo de espera).

El uso sería:

 getFive(onComplete); 

Que debería alertar “5” a la pantalla. (Violín) .

Soluciones posibles

Básicamente, hay dos formas de resolver esto:

  1. Haga que la llamada AJAX sea sincrónica (vamos a llamarla SJAX).
  2. Reestructura tu código para que funcione correctamente con devoluciones de llamadas.

1. AJAX sincrónico – ¡No lo hagas!

En cuanto a AJAX síncrono, ¡no lo hagas! La respuesta de Félix plantea algunos argumentos convincentes sobre por qué es una mala idea. En resumen, congelará el navegador del usuario hasta que el servidor devuelva la respuesta y cree una experiencia de usuario muy mala. Aquí hay otro breve resumen tomado de MDN sobre por qué:

XMLHttpRequest admite comunicaciones síncronas y asíncronas. En general, sin embargo, las solicitudes asincrónicas deberían preferirse a las solicitudes síncronas por motivos de rendimiento.

En resumen, las solicitudes síncronas bloquean la ejecución del código … … esto puede causar problemas graves …

Si tiene que hacerlo, puede pasar una bandera: Aquí está cómo:

 var request = new XMLHttpRequest(); request.open('GET', 'yourURL', false); // `false` makes the request synchronous request.send(null); if (request.status === 200) {// That's HTTP for 'ok' console.log(request.responseText); } 

2. Reestructurar el código

Deja que tu función acepte una callback. En el código de ejemplo foo se puede hacer para aceptar una callback. Le diremos a nuestro código cómo reactjsr cuando foo finalice.

Asi que:

 var result = foo(); // code that depends on `result` goes here 

Se convierte en:

 foo(function(result) { // code that depends on `result` }); 

Aquí pasamos una función anónima, pero igual podríamos pasar una referencia a una función existente, haciendo que se vea así:

 function myHandler(result) { // code that depends on `result` } foo(myHandler); 

Para obtener más detalles sobre cómo se realiza este tipo de diseño de callback, consulte la respuesta de Felix.

Ahora, definamos foo para actuar en consecuencia

 function foo(callback) { var httpRequest = new XMLHttpRequest(); httpRequest.onload = function(){ // when the request is loaded callback(httpRequest.responseText);// we're calling our method }; httpRequest.open('GET', "/echo/json"); httpRequest.send(); } 

(violín)

Ahora hemos hecho que nuestra función foo acepte una acción para ejecutar cuando el AJAX se complete con éxito, podemos extender esto más al verificar si el estado de la respuesta no es 200 y actuar en consecuencia (crear un controlador de fallas y tal). Resolviendo nuestro problema de manera efectiva.

Si aún le cuesta entender esto, lea la guía de introducción de AJAX en MDN.

XMLHttpRequest 2 (antes que nada lea las respuestas de Benjamin Gruenbaum y Felix Kling)

Si no utiliza jQuery y quiere un pequeño XMLHttpRequest 2 que funcione en los navegadores modernos y también en los navegadores móviles, sugiero usarlo de esta manera:

 function ajax(a, b, c){ // URL, callback, just a placeholder c = new XMLHttpRequest; c.open('GET', a); c.onload = b; c.send() } 

Como puedes ver:

  1. Es más corto que todas las demás funciones enumeradas.
  2. La callback se establece directamente (por lo que no hay cierres adicionales innecesarios).
  3. Utiliza la nueva carga (por lo que no es necesario comprobar el estado de estado listo &&)
  4. Hay algunas otras situaciones que no recuerdo que hacen que XMLHttpRequest 1 sea molesto.

Hay dos formas de obtener la respuesta de esta llamada Ajax (tres usando el nombre XMLHttpRequest var):

Lo más simple:

 this.response 

O si por algún motivo bind() la callback a una clase:

 e.target.response 

Ejemplo:

 function callback(e){ console.log(this.response); } ajax('URL', callback); 

O (lo anterior es mejor las funciones anónimas siempre son un problema):

 ajax('URL', function(e){console.log(this.response)}); 

Nada más fácil.

Ahora algunas personas probablemente dirán que es mejor usar onreadystatechange o incluso el nombre de la variable XMLHttpRequest. Eso está mal.

Echa un vistazo a las funciones avanzadas de XMLHttpRequest

Es compatible con todos * navegadores modernos. Y puedo confirmar que estoy usando este enfoque ya que XMLHttpRequest 2 existe. Nunca tuve ningún tipo de problema en todos los navegadores que uso.

onreadystatechange solo es útil si desea obtener los encabezados en el estado 2.

Usar el nombre de la variable XMLHttpRequest es otro gran error ya que necesita ejecutar la callback dentro de los cierres onload / oreadystatechange, de lo contrario lo perdió.


Ahora, si desea algo más complejo utilizando post y FormData, puede extender fácilmente esta función:

 function x(a, b, e, d, c){ // URL, callback, method, formdata or {key:val},placeholder c = new XMLHttpRequest; c.open(e||'get', a); c.onload = b; c.send(d||null) } 

De nuevo … es una función muy corta, pero sí recibe y publica.

Ejemplos de uso:

 x(url, callback); // By default it's get so no need to set x(url, callback, 'post', {'key': 'val'}); // No need to set post data 

O pase un elemento de formulario completo ( document.getElementsByTagName('form')[0] ):

 var fd = new FormData(form); x(url, callback, 'post', fd); 

O establece algunos valores personalizados:

 var fd = new FormData(); fd.append('key', 'val') x(url, callback, 'post', fd); 

Como pueden ver, no implementé la sincronización … es algo malo.

Habiendo dicho eso … ¿por qué no hacerlo de la manera fácil?


Como se menciona en el comentario, el uso del error && synchronous rompe completamente el punto de la respuesta. ¿Cuál es una buena manera de usar Ajax de la manera adecuada?

Manejador de errores

 function x(a, b, e, d, c){ // URL, callback, method, formdata or {key:val}, placeholder c = new XMLHttpRequest; c.open(e||'get', a); c.onload = b; c.onerror = error; c.send(d||null) } function error(e){ console.log('--Error--', this.type); console.log('this: ', this); console.log('Event: ', e) } function displayAjax(e){ console.log(e, this); } x('WRONGURL', displayAjax); 

En el script anterior, tiene un controlador de errores que está estáticamente definido para que no comprometa la función. El controlador de errores también se puede usar para otras funciones.

Pero para realmente sacar un error, la única forma es escribir una URL incorrecta, en cuyo caso cada navegador arroja un error.

Los manejadores de errores pueden ser útiles si configura encabezados personalizados, configura el tipo de respuesta para blob array buffer o lo que sea ….

Incluso si pasa ‘POSTAPAPAP’ como método, no arrojará un error.

Incluso si pasa ‘fdggdgilfdghfldj’ como formdata no arrojará un error.

En el primer caso, el error está dentro de la this.statusText displayAjax() debajo de this.statusText como Method not Allowed .

En el segundo caso, simplemente funciona. Debe verificar en el lado del servidor si pasó los datos de la publicación correcta.

dominio cruzado no permitido arroja error automáticamente.

En la respuesta de error, no hay códigos de error.

Solo está el this.type que está configurado como error.

¿Por qué agregar un controlador de errores si no tiene control sobre los errores? La mayoría de los errores se devuelven dentro de este en la función de callback displayAjax() .

Entonces: no es necesario verificar los errores si puede copiar y pegar la URL correctamente. 😉

PD: Como la primera prueba, escribí x (‘x’, displayAjax) …, ¿y obtuvo una respuesta totalmente … ??? Así que revisé la carpeta donde se encuentra el HTML, y había un archivo llamado ‘x.xml’. Entonces, incluso si olvida la extensión de su archivo, XMLHttpRequest 2 LA ENCONTRARÁ . LOL’d


Leer un archivo sincrónico

No hagas eso.

Si desea bloquear el navegador por un tiempo, cargue un buen archivo txt grande sincrónico.

 function omg(a, c){ // URL c = new XMLHttpRequest; c.open('GET', a, true); c.send(); return c; // Or c.response } 

Ahora puedes hacer

  var res = omg('thisIsGonnaBlockThePage.txt'); 

No hay otra manera de hacer esto de una manera no asincrónica. (Sí, con setTimeout loop … ¿pero en serio?)

Otro punto es … si trabajas con API o solo con los propios archivos de la lista o lo que sea, siempre utilizas diferentes funciones para cada solicitud …

Solo si tiene una página donde carga siempre el mismo XML / JSON o lo que sea, solo necesita una función. En ese caso, modifique un poco la función Ajax y reemplace b con su función especial.


Las funciones anteriores son para uso básico.

Si desea EXTENDER la función …

Sí tu puedes.

Estoy usando muchas API y una de las primeras funciones que integro en cada página HTML es la primera función Ajax en esta respuesta, con GET solo …

Pero puedes hacer muchas cosas con XMLHttpRequest 2:

Creé un administrador de descargas (usando rangos en ambos lados con currículum, lector de archivos, sistema de archivos), varios convertidores de resizer de imágenes usando canvas, rellenando bases de datos websql con base64images y mucho más … Pero en estos casos debes crear una función solo para ese propósito … a veces necesitas un blob, buffers de matriz, puedes establecer encabezados, anular el tipo mimet y hay mucho más …

Pero la pregunta aquí es cómo devolver una respuesta Ajax … (Agregué una manera fácil).

Si está utilizando promesas, esta respuesta es para usted.

Esto significa AngularJS, jQuery (con diferido), reemplazo XHR nativo (fetch), EmberJS, guardar de BackboneJS o cualquier biblioteca de nodos que devuelve promesas.

Tu código debe ser algo así como esto:

 function foo() { var data; // or $.get(...).then, or request(...).then, or query(...).then fetch("/echo/json").then(function(response){ data = response.json(); }); return data; } var result = foo(); // result is always undefined no matter what. 

Félix Kling hizo un buen trabajo al escribir una respuesta para las personas que usan jQuery con devoluciones de llamada para AJAX. Tengo una respuesta para XHR nativo. Esta respuesta es para el uso genérico de las promesas, ya sea en la interfaz o back-end.


El problema central

El modelo de simultaneidad de JavaScript en el navegador y en el servidor con NodeJS / io.js es asincrónico y reactivo .

Cada vez que llamas a un método que devuelve una promesa, los manejadores de then siempre se ejecutan de forma asíncrona, es decir, después del código debajo de ellos que no está en un controlador .then .

Esto significa que cuando estás devolviendo data el controlador que has definido no se ejecutó aún. Esto a su vez significa que el valor que está devolviendo no se ha establecido en el valor correcto en el tiempo.

Aquí hay una analogía simple para el problema:

  function getFive(){ var data; setTimeout(function(){ // set a timer for one second in the future data = 5; // after a second, do this }, 1000); return data; } document.body.innerHTML = getFive(); // `undefined` here and not 5 

You are using Ajax incorrectly. The idea is not to have it return anything, but instead hand off the data to something called a callback function, which handles the data.

Es decir:

 function handleData( responseData ) { // Do what you want with the data console.log(responseData); } $.ajax({ url: "hi.php", ... success: function ( data, status, XHR ) { handleData(data); } }); 

Returning anything in the submit handler will not do anything. You must instead either hand off the data, or do what you want with it directly inside the success function.

The simplest solution is create a JavaScript function and call it for the Ajax success callback.

 function callServerAsync(){ $.ajax({ url: '...', success: function(response) { successCallback(response); } }); } function successCallback(responseObj){ // Do something like read the response and show data alert(JSON.stringify(responseObj)); // Only applicable to JSON response } function foo(callback) { $.ajax({ url: '...', success: function(response) { return callback(null, response); } }); } var result = foo(function(err, result){ if (!err) console.log(result); }); 

I will answer with a horrible-looking, hand-drawn comic. The second image is the reason why result is undefined in your code example.

enter image description here

Angular1

For people who are using AngularJS , can handle this situation using Promises .

Here it says,

Promises can be used to unnest asynchronous functions and allows one to chain multiple functions together.

You can find a nice explanation here also.

Example found in docs mentioned below.

  promiseB = promiseA.then( function onSuccess(result) { return result + 1; } ,function onError(err) { //Handle error } ); // promiseB will be resolved immediately after promiseA is resolved // and its value will be the result of promiseA incremented by 1. 

Angular2 and Later

In Angular2 with look at the following example, but its recommended to use Observables with Angular2 .

  search(term: string) { return this.http .get(`https://api.spotify.com/v1/search?q=${term}&type=artist`) .map((response) => response.json()) .toPromise(); 

}

You can consume that in this way,

 search() { this.searchService.search(this.searchField.value) .then((result) => { this.result = result.artists.items; }) .catch((error) => console.error(error)); } 

See the original post here. But Typescript does not support native es6 Promises , if you want to use it, you might need plugin for that.

Additionally here is the promises spec define here.

Most of the answers here give useful suggestions for when you have a single async operation, but sometimes, this comes up when you need to do an asynchronous operation for each entry in an array or other list-like structure. The temptation is to do this:

 // WRONG var results = []; theArray.forEach(function(entry) { doSomethingAsync(entry, function(result) { results.push(result); }); }); console.log(results); // Eg, using them, returning them, etc. 

Ejemplo:

 // WRONG var theArray = [1, 2, 3]; var results = []; theArray.forEach(function(entry) { doSomethingAsync(entry, function(result) { results.push(result); }); }); console.log("Results:", results); // Eg, using them, returning them, etc. function doSomethingAsync(value, callback) { console.log("Starting async operation for " + value); setTimeout(function() { console.log("Completing async operation for " + value); callback(value * 2); }, Math.floor(Math.random() * 200)); } 
 .as-console-wrapper { max-height: 100% !important; } 

Have a look at this example:

 var app = angular.module('plunker', []); app.controller('MainCtrl', function($scope,$http) { var getJoke = function(){ return $http.get('http://api.icndb.com/jokes/random').then(function(res){ return res.data.value; }); } getJoke().then(function(res) { console.log(res.joke); }); }); 

As you can see getJoke is returning a resolved promise (it is resolved when returning res.data.value ). So you wait until the $http.get request is completed and then console.log(res.joke) is executed (as a normal asynchronous flow).

This is the plnkr:

http://embed.plnkr.co/XlNR7HpCaIhJxskMJfSg/

Another approach to return a value from an asynchronous function, is to pass in an object that will store the result from the asynchronous function.

Here is an example of the same:

 var async = require("async"); // This wires up result back to the caller var result = {}; var asyncTasks = []; asyncTasks.push(function(_callback){ // some asynchronous operation $.ajax({ url: '...', success: function(response) { result.response = response; _callback(); } }); }); async.parallel(asyncTasks, function(){ // result is available after performing asynchronous operation console.log(result) console.log('Done'); }); 

I am using the result object to store the value during the asynchronous operation. This allows the result be available even after the asynchronous job.

I use this approach a lot. I would be interested to know how well this approach works where wiring the result back through consecutive modules is involved.

This is one of the places which two ways data binding that’s used in many new JavaScript frameworks will work greatly for you…

So if you are using Angular, React or any other frameworks which do two ways data binding, this issue is simply fixed for you, so in easy word, your result is undefined at the first stage, so you have got result = undefined before you receive the data, then as soon as you get the result, it will updated and get assigned to the new value which is respond of your Ajax call…

But how you can do it in pure javascript or jQuery for example as you asked in this question?

You can use a callback , promise and recently observable to handle it for you, for example in promises we have some function like success() or then() which will be executed when your data is ready for you, same with callback or subscribe function on observable .

For example in your case which you are using jQuery , you can do something like this:

 $(document).ready(function(){ function foo() { $.ajax({url: "api/data", success: function(data){ fooDone(data); //after we have data, we pass it to fooDone }}); }; function fooDone(data) { console.log(data); //fooDone has the data and console.log it }; foo(); //call happens here }); 

For more information study about promises and observables which are newer ways to do this async stuffs.

While promises and callbacks work fine in many situations, it is a pain in the rear to express something like:

 if (!name) { name = async1(); } async2(name); 

You’d end up going through async1 ; check if name is undefined or not and call the callback accordingly.

 async1(name, callback) { if (name) callback(name) else { doSomething(callback) } } async1(name, async2) 

While it is okay in small examples it gets annoying when you have a lot of similar cases and error handling involved.

Fibers helps in solving the issue.

 var Fiber = require('fibers') function async1(container) { var current = Fiber.current var result doSomething(function(name) { result = name fiber.run() }) Fiber.yield() return result } Fiber(function() { var name if (!name) { name = async1() } async2(name) // Make any number of async calls from here } 

You can checkout the project here .

Short answer is, you have to implement a callback like this:

 function callback(response) { // Here you can do what ever you want with the response object. console.log(response); } $.ajax({ url: "...", success: callback }); 

The following example I have written shows how to

  • Handle asynchronous HTTP calls;
  • Wait for response from each API call;
  • Use Promise pattern;
  • Use Promise.All pattern to join multiple HTTP calls;

This working example is self-contained. It will define a simple request object that uses the window XMLHttpRequest object to make calls. It will define a simple function to wait for a bunch of promises to be completed.

Context. The example is querying the Spotify Web API endpoint in order to search for playlist objects for a given set of query strings:

 [ "search?type=playlist&q=%22doom%20metal%22", "search?type=playlist&q=Adele" ] 

For each item, a new Promise will fire a block – ExecutionBlock , parse the result, schedule a new set of promises based on the result array, that is a list of Spotify user objects and execute the new HTTP call within the ExecutionProfileBlock asynchronously.

You can then see a nested Promise structure, that lets you spawn multiple and completely asynchronous nested HTTP calls, and join the results from each subset of calls through Promise.all .

NOTE Recent Spotify search APIs will require an access token to be specified in the request headers:

 -H "Authorization: Bearer {your access token}" 

So, you to run the following example you need to put your access token in the request headers:

 var spotifyAccessToken = "YourSpotifyAccessToken"; var console = { log: function(s) { document.getElementById("console").innerHTML += s + "
" } } // Simple XMLHttpRequest // based on https://davidwalsh.name/xmlhttprequest SimpleRequest = { call: function(what, response) { var request; if (window.XMLHttpRequest) { // Mozilla, Safari, ... request = new XMLHttpRequest(); } else if (window.ActiveXObject) { // Internet Explorer try { request = new ActiveXObject('Msxml2.XMLHTTP'); } catch (e) { try { request = new ActiveXObject('Microsoft.XMLHTTP'); } catch (e) {} } } // State changes request.onreadystatechange = function() { if (request.readyState === 4) { // Done if (request.status === 200) { // Complete response(request.responseText) } else response(); } } request.open('GET', what, true); request.setRequestHeader("Authorization", "Bearer " + spotifyAccessToken); request.send(null); } } //PromiseAll var promiseAll = function(items, block, done, fail) { var self = this; var promises = [], index = 0; items.forEach(function(item) { promises.push(function(item, i) { return new Promise(function(resolve, reject) { if (block) { block.apply(this, [item, index, resolve, reject]); } }); }(item, ++index)) }); Promise.all(promises).then(function AcceptHandler(results) { if (done) done(results); }, function ErrorHandler(error) { if (fail) fail(error); }); }; //promiseAll // LP: deferred execution block var ExecutionBlock = function(item, index, resolve, reject) { var url = "https://api.spotify.com/v1/" url += item; console.log( url ) SimpleRequest.call(url, function(result) { if (result) { var profileUrls = JSON.parse(result).playlists.items.map(function(item, index) { return item.owner.href; }) resolve(profileUrls); } else { reject(new Error("call error")); } }) } arr = [ "search?type=playlist&q=%22doom%20metal%22", "search?type=playlist&q=Adele" ] promiseAll(arr, function(item, index, resolve, reject) { console.log("Making request [" + index + "]") ExecutionBlock(item, index, resolve, reject); }, function(results) { // Aggregated results console.log("All profiles received " + results.length); //console.log(JSON.stringify(results[0], null, 2)); ///// promiseall again var ExecutionProfileBlock = function(item, index, resolve, reject) { SimpleRequest.call(item, function(result) { if (result) { var obj = JSON.parse(result); resolve({ name: obj.display_name, followers: obj.followers.total, url: obj.href }); } //result }) } //ExecutionProfileBlock promiseAll(results[0], function(item, index, resolve, reject) { //console.log("Making request [" + index + "] " + item) ExecutionProfileBlock(item, index, resolve, reject); }, function(results) { // aggregated results console.log("All response received " + results.length); console.log(JSON.stringify(results, null, 2)); } , function(error) { // Error console.log(error); }) ///// }, function(error) { // Error console.log(error); });
 

You can use this custom library (written using Promise) to make a remote call.

 function $http(apiConfig) { return new Promise(function (resolve, reject) { var client = new XMLHttpRequest(); client.open(apiConfig.method, apiConfig.url); client.send(); client.onload = function () { if (this.status >= 200 && this.status < 300) { // Performs the function "resolve" when this.status is equal to 2xx. // Your logic here. resolve(this.response); } else { // Performs the function "reject" when this.status is different than 2xx. reject(this.statusText); } }; client.onerror = function () { reject(this.statusText); }; }); } 

Simple usage example:

 $http({ method: 'get', url: 'google.com' }).then(function(response) { console.log(response); }, function(error) { console.log(error) }); 

2017 answer: you can now do exactly what you want in every current browser and node

This is quite simple:

  • Return a Promise
  • Use the ‘await’ , which will tell JavaScript to await the promise to be resolved into a vlue (like the hTTP response)
  • Add the ‘async’ keyword to the parent function

Here’s a working version of your code:

 (async function(){ var response = await superagent.get('...') console.log(response) })() 

await is supported in all current browsers and node 8

Another solution is to execute code via sequential executor nsynjs .

If underlying function is promisified

nsynjs will evaluate all promises sequentially, and put promise result into data property:

 function synchronousCode() { var getURL = function(url) { return window.fetch(url).data.text().data; }; var url = 'https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js'; console.log('received bytes:',getURL(url).length); }; nsynjs.run(synchronousCode,{},function(){ console.log('synchronousCode done'); }); 
  

Js is a single threaded.

Browser can be divided into three parts:

1)Event Loop

2)Web API

3)Event Queue

Event Loop runs for forever ie kind of infinite loop.Event Queue is where all your function are pushed on some event(example:click) this is one by one carried out of queue and put into Event loop which execute this function and prepares it self for next one after first one is executed.This means Execution of one function doesn’t starts till the function before it in queue is executed in event loop.

Now let us think we pushed two functions in a queue one is for getting a data from server and another utilises that data.We pushed the serverRequest() function in queue first then utiliseData() function. serverRequest function goes in event loop and makes a call to server as we never know how much time it will take to get data from server so this process is expected to take time and so we busy our event loop thus hanging our page, that’s where Web API come into role it take this function from event loop and deals with server making event loop free so that we can execute next function from queue.The next function in queue is utiliseData() which goes in loop but because of no data available it goes waste and execution of next function continues till end of the queue.(This is called Async calling ie we can do something else till we get data)

Let suppose our serverRequest() function had a return statement in a code, when we get back data from server Web API will push it in queue at the end of queue. As it get pushed at end in queue we cannot utilise its data as there is no function left in our queue to utilise this data. Thus it is not possible to return something from Async Call.

Thus Solution to this is callback or promise .

A Image from one of the answers here, Correctly explains callback use… We give our function(function utilising data returned from server) to function calling server.

CallBack

  function doAjax(callbackFunc, method, url) { var xmlHttpReq = new XMLHttpRequest(); xmlHttpReq.open(method, url); xmlHttpReq.onreadystatechange = function() { if (xmlHttpReq.readyState == 4 && xmlHttpReq.status == 200) { callbackFunc(xmlHttpReq.responseText); } } xmlHttpReq.send(null); } 

In my Code it is called as

 function loadMyJson(categoryValue){ if(categoryValue==="veg") doAjax(print,"GET","http://localhost:3004/vegetables"); else if(categoryValue==="fruits") doAjax(print,"GET","http://localhost:3004/fruits"); else console.log("Data not found"); } 

Read here for new methods in ECMA(2016/17) for making async call(@Felix Kling Answer on Top) https://stackoverflow.com/a/14220323/7579856

Here are some approaches to work with asynchronous requests:

  1. Browser Promise object
  2. Q – A promise library for JavaScript
  3. A+ Promises.js
  4. jQuery deferred
  5. XMLHttpRequest API
  6. Using callback concept – As implementation in first answer

Example: jQuery deferred implementation to work with multiple requests

 var App = App || {}; App = { getDataFromServer: function(){ var self = this, deferred = $.Deferred(), requests = []; requests.push($.getJSON('request/ajax/url/1')); requests.push($.getJSON('request/ajax/url/2')); $.when.apply(jQuery, requests).done(function(xhrResponse) { return deferred.resolve(xhrResponse.result); }); return deferred; }, init: function(){ this.getDataFromServer().done(_.bind(function(resp1, resp2) { // Do the operations which you wanted to do when you // get a response from Ajax, for example, log response. }, this)); } }; App.init(); 

ECMAScript 6 has ‘generators’ which allow you to easily program in an asynchronous style.

 function* myGenerator() { const callback = yield; let [response] = yield $.ajax("https://stackoverflow.com", {complete: callback}); console.log("response is:", response); // examples of other things you can do yield setTimeout(callback, 1000); console.log("it delayed for 1000ms"); while (response.statusText === "error") { [response] = yield* anotherGenerator(); } } 

To run the above code you do this:

 const gen = myGenerator(); // Create generator gen.next(); // Start it gen.next((...args) => gen.next([...args])); // Set its callback function 

If you need to target browsers that don’t support ES6 you can run the code through Babel or closure-compiler to generate ECMAScript 5.

The callback ...args are wrapped in an array and destructured when you read them so that the pattern can cope with callbacks that have multiple arguments. For example with node fs :

 const [err, data] = yield fs.readFile(filePath, "utf-8", callback); 

Use a callback() function inside the foo() success. Try in this way. It is simple and easy to understand.

 var lat = ""; var lon = ""; function callback(data) { lat = data.lat; lon = data.lon; } function getLoc() { var url = "http://ip-api.com/json" $.getJSON(url, function(data) { callback(data); }); } getLoc(); 

Short answer : Your foo() method returns immediately, while the $ajax() call executes asynchronously after the function returns . The problem is then how or where to store the results retrieved by the async call once it returns.

Several solutions have been given in this thread. Perhaps the easiest way is to pass an object to the foo() method, and to store the results in a member of that object after the async call completes.

 function foo(result) { $.ajax({ url: '...', success: function(response) { result.response = response; // Store the async result } }); } var result = { response: null }; // Object to hold the async result foo(result); // Returns before the async completes 

Note that the call to foo() will still return nothing useful. However, the result of the async call will now be stored in result.response .

It’s a very common issue we face while struggling with the ‘mysteries’ of JavaScript. Let me try demystifying this mystery today.

Let’s start with a simple JavaScript function:

 function foo(){ // do something return 'wohoo'; } let bar = foo(); // bar is 'wohoo' here 

That’s a simple synchronous function call (where each line of code executed one after other in sequence), and the result is same as expected.

Now let’s add a bit of twist, by introducing little delay in our function, so that all lines of code are not executed in sequence. Thus, it will emulate the asynchronous behavior of function :

 function foo(){ setTimeout( ()=>{ return 'wohoo'; }, 1000 ) } let bar = foo() // bar is undefined here 

So there you go, that delay just broke the functionality we expected ! But what exactly happened ? Well, it’s actually pretty logical if you look at the code. the function foo() , upon execution, returns nothing (thus returned value is undefined ), but it does start a timer, which executes a function after 1s to return ‘wohoo’. But as you can see, the value that’s assigned to bar is the immediately returned stuff from foo(), not anything else that comes later.

So, how do we tackle this issue?

Let’s ask our function for a PROMISE . Promise is really about what it means : it means that the function guarantees you to provide with any output it gets in future. so let’s see it in action for our little problem above :

 function foo(){ return new Promise( (resolve, reject) => { // I want foo() to PROMISE me something setTimeout ( function(){ // promise is RESOLVED , when exececution reaches this line of code resolve('wohoo')// After 1 second, RESOLVE the promise with value 'wohoo' }, 1000 ) }) } let bar ; foo().then( res => { bar = res; console.log(bar) // will print 'wohoo' }); 

Thus, the summary is – to tackle the asynchronous functions like ajax based calls etc., you can use a promise to resolve the value (which you intend to return). Thus, in short you resolve value instead of returning , in asynchronous functions.

Of course there are many approaches like synchronous request, promise, but from my experience I think you should use the callback approach. It’s natural to asynchronous behavior of Javascript. So, your code snippet can be rewrite a little different:

 function foo() { var result; $.ajax({ url: '...', success: function(response) { myCallback(response); } }); return result; } function myCallback(response) { // Does something. } 

The question was:

How do I return the response from an asynchronous call?

which CAN be interpreted as:

How to make asynchronous code look synchronous ?

The solution will be to avoid callbacks, and use a combination of Promises and async/await .

I would like to give an example for a Ajax request.

(Although it can be written in Javascript, I prefer to write it in Python, and compile it to Javascript using Transcrypt . It will be clear enough.)

Lets first enable JQuery usage, to have $ available as S :

 __pragma__ ('alias', 'S', '$') 

Define a function which returns a Promise , in this case an Ajax call:

 def read(url: str): deferred = S.Deferred() S.ajax({'type': "POST", 'url': url, 'data': { }, 'success': lambda d: deferred.resolve(d), 'error': lambda e: deferred.reject(e) }) return deferred.promise() 

Use the asynchronous code as if it were synchronous :

 async def readALot(): try: result1 = await read("url_1") result2 = await read("url_2") except Exception: console.warn("Reading a lot failed") 

We find ourselves in a universe which appears to progress along a dimension we call “time”. We don’t really understand what time is, but we have developed abstractions and vocabulary that let us reason and talk about it: “past”, “present”, “future”, “before”, “after”.

The computer systems we build–more and more–have time as an important dimension. Certain things are set up to happen in the future. Then other things need to happen after those first things eventually occur. This is the basic notion called “asynchronicity”. In our increasingly networked world, the most common case of asynchonicity is waiting for some remote system to response to some request.

Consider an example. You call the milkman and order some milk. When it comes, you want to put it in your coffee. You can’t put the milk in your coffee right now, because it is not here yet. You have to wait for it to come before putting it in your coffee. In other words, the following won’t work:

 var milk = order_milk(); put_in_coffee(milk); 

Because JS has no way to know that it needs to wait for order_milk to finish before it executes put_in_coffee . In other words, it does not know that order_milk is asynchronous –is something that is not going to result in milk until some future time. JS, and other declarative languages, execute one statement after another without waiting.

The classic JS approach to this problem, taking advantage of the fact that JS supports functions as first-class objects which can be passed around, is to pass a function as a parameter to the asynchonous request, which it will then invoke when it has complete its task sometime in the future. That is the “callback” approach. Se parece a esto:

 order_milk(put_in_coffee); 

order_milk kicks off, orders the milk, then, when and only when it arrives, it invokes put_in_coffee .

The problem with this callback approach is that it pollutes the normal semantics of a function reporting its result with return ; instead, functions must nost reports their results by calling a callback given as a parameter. Also, this approach can rapidly become unwieldy when dealing with longer sequences of events. For example, let’s say that I want to wait for the milk to be put in the coffee, and then and only then perform a third step, namely drinking the coffee. I end up needing to write something like this:

 order_milk(function(milk) { put_in_coffee(milk, drink_coffee); } 

where I am passing to put_in_coffee both the milk to put in it, and also the action ( drink_coffee ) to execute once the milk has been put in. Such code becomes hard to write, and read, and debug.

In this case, we could rewrite the code in the question as:

 var answer; $.ajax('/foo.json') . done(function(response) { callback(response.data); }); function callback(data) { console.log(data); } 

Enter promises

This was the motivation for the notion of a “promise”, which is a particular type of value which represents a future or asynchronous outcome of some sort. It can represent something that already happened, or that is going to happen in the future, or might never happen at all. Promises have a single method, named then , to which you pass an action to be executed when the outcome the promise represents has been realized.

In the case of our milk and coffee, we design order_milk to return a promise for the milk arriving, then specify put_in_coffee as a then action, as follows:

 order_milk() . then(put_in_coffee) 

One advantage of this is that we can string these together to create sequences of future occurrences (“chaining”):

 order_milk() . then(put_in_coffee) . then(drink_coffee) 

Let’s apply promises to your particular problem. We will wrap our request logic inside a function, which returns a promise:

 function get_data() { return $.ajax('/foo.json'); } 

Actually, all we’ve done is added a return to the call to $.ajax . This works because jQuery’s $.ajax already returns a kind of promise-like thing. (In practice, without getting into details, we would prefer to wrap this call so as return a real promise, or use some alternative to $.ajax that does so.) Now, if we want to load the file and wait for it to finish and then do something, we can simply say

 get_data() . then(do_something) 

por ejemplo,

 get_data() . then(function(data) { console.log(data); }); 

When using promises, we end up passing lots of functions into then , so it’s often helpful to use the more compact ES6-style arrow functions:

 get_data() . then(data => console.log(data)); 

The async keyword

But there’s still something vaguely dissatisfying about having to write code one way if synchronous and a quite different way if asynchronous. For synchronous, we write

 a(); b(); 

but if a is asynchronous, with promises we have to write

 a() . then(b); 

Above, we said “JS has no way to know that it needs to wait for the first call to finish before it executes the second”. Wouldn’t it be nice if there was some way to tell JS that? It turns out that there is–the await keyword, used inside a special type of function called an “async” function. This feature is part of the upcoming version of ES, but is already available in transpilers such as Babel given the right presets. This allows us to simply write

 async function morning_routine() { var milk = await order_milk(); var coffee = await put_in_coffee(milk); await drink(coffee); } 

In your case, you would be able to write something like

 async function foo() { data = await get_data(); console.log(data); } 

Using ES2017 you should have this as the function declaration

 async function foo() { var response = await $.ajax({url: '...'}) return response; } 

And executing it like this.

 (async function() { try { var result = await foo() console.log(result) } catch (e) {} })() 

Or the Promise syntax

 foo().then(response => { console.log(response) }).catch(error => { console.log(error) }) 

Let’s see the forest first before looking at the trees.

There are many informative answers with great details here, I won’t repeat any of them. The key to programming in JavaScript is having first the correct mental model of overall execution.

  1. Your entry point(s) is executed as the result of an event. For example, a script tag with code is loaded into the browser. (Accordingly, this is why you may need to be concerned with the readiness of the page to run your code if it requires dom elements to be constructed first, etc.)
  2. Your code executes to completion–however many asynchronous calls it makes–without executing any of your callbacks, including XHR requests, set timeouts, dom event handlers, etc. Each of those callbacks waiting to be executed will sit in a queue, waiting their turn to be run after other events that fired have all finished execution.
  3. Each individual callback to an XHR request, set timeout or dom the event once invoked will then run to completion.

The good news is that if you understand this point well, you will never have to worry about race conditions. You should first and foremost thing of how you want to organize your code as essentially the response to different discrete events, and how you want to thread them together into a logical sequence. You can use promises or higher level new async/await as tools to that end, or you can roll your own.

But you shouldn’t use any tactical tools to solve a problem until you are comfortable with the actual problem domain. Draw a map of these dependencies to know what needs to run when. Attempting an ad-hoc approach to all these callbacks is just not going to serve you well.

Rather than throwing code at you, there are 2 concepts that are key to understanding how JS handles callbacks and asynchronicity. (is that even a word?)

The Event Loop and Concurrency Model

There are three things you need to be aware of; The queue; the event loop and the stack

In broad, simplistic terms, the event loop is like the project manager, it is constantly listening for any functions that want to run and communicates between the queue and the stack.

 while (queue.waitForMessage()) { queue.processNextMessage(); } 

Once it receives a message to run something it adds it to the queue. The queue is the list of things that are waiting to execute (like your AJAX request). imagine it like this:

  1. call foo.com/api/bar using foobarFunc 2. Go perform an infinite loop ... and so on 

When one of these messages is going to execute it pops the message from the queue and creates a stack, the stack is everything JS needs to execute to perform the instruction in the message. So in our example it’s being told to call foobarFunc

 function foobarFunc (var) { console.log(anotherFunction(var)); } 

So anything that foobarFunc needs to execute (in our case anotherFunction ) will get pushed onto the stack. executed, and then forgotten about – the event loop will then move onto the next thing in the queue (or listen for messages)

The key thing here is the order of execution. That is

WHEN is something going to run

When you make a call using AJAX to an external party or run any asynchronous code (a setTimeout for example), Javascript is dependant upon a response before it can proceed.

The big question is when will it get the response? The answer is we don’t know – so the event loop is waiting for that message to say “hey run me”. If JS just waited around for that message synchronously your app would freeze and it will suck. So JS carries on executing the next item in the queue whilst waiting for the message to get added back to the queue.

That’s why with asynchronous functionality we use things called callbacks . It’s kinda like a promise quite literally. As in I promise to return something at some point jQuery uses specific callbacks called deffered.done deffered.fail and deffered.always (amongst others). You can see them all here

So what you need to do is pass a function that is promised to execute at some point with data that is passed to it.

Because a callback is not executed immediately but at a later time it’s important to pass the reference to the function not it executed. asi que

 function foo(bla) { console.log(bla) } 

so most of the time (but not always) you’ll pass foo not foo()

Hopefully that will make some sense. When you encounter things like this that seem confusing – i highly recommend reading the documentation fully to at least get an understanding of it. It will make you a much better developer.