¿Cómo puedo devolver la respuesta de una llamada asincrónica?

Cómo puedo devolver la respuesta/resulto de una función foo ¿Eso hace una petición asincrónica?

Estoy tratando de devolver el valor del callback, así como asignar el resultado a una variable local dentro de la función y devolverlo, pero ninguna de esas maneras realmente devuelven la respuesta - todos vuelven undefined o sea el valor inicial de la variable result Lo es.

Ejemplo de una función asincrónica que acepta un callback (usando jQuery's ajax función):

function foo() {
    var result;

    $.ajax({
        url: '...',
        success: function(response) {
            result = response;
            // return response; // <- I tried that one as well
        }
    });

    return result; // It always returns `undefined`
}

Ejemplo utilizando Node.js:

function foo() {
    var result;

    fs.readFile("path/to/file", function(err, data) {
        result = data;
        // return data; // <- I tried that one as well
    });

    return result; // It always returns `undefined`
}

Ejemplo utilizando then bloque de una promesa:

function foo() {
    var result;

    fetch(url).then(function(response) {
        result = response;
        // return response; // <- I tried that one as well
    });

    return result; // It always returns `undefined`
}

Pregunta hecha hace 11 años, 4 meses, 10 días - Por codeglitch


11 Respuestas:

  • → Para una explicación más general del comportamiento asincrónico con diferentes ejemplos, véase ¿Por qué mi variable no se altera después de modificarla dentro de una función? - Referencia de código asincrónico

    → Si usted ya entiende el problema, omita las posibles soluciones a continuación.

    El problema

    El A dentro Ajax stands asincrónico. Esto significa que el envío de la solicitud (o más bien recibir la respuesta) se saca del flujo normal de ejecución. En su ejemplo, $.ajax vuelve inmediatamente y la siguiente declaración, return result;, se ejecuta antes de la función que pasó como success Callback fue llamado.

    Aquí hay una analogía que espera que la diferencia entre el flujo sincronizado y asincrónico sea más clara:

    Sincrónico

    Imagina que haces una llamada a un amigo y le pides que busque algo para ti. Aunque podría tardar un tiempo, espera por teléfono y mira hacia el espacio, hasta que tu amigo te dé la respuesta que necesitabas.

    Lo mismo ocurre cuando haces una llamada de función que contiene 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 ejecutar, cualquier código que viene después var item = findItem(); tiene que Espera. hasta que la función devuelve el resultado.

    Asincrónico

    Vuelve a llamar a tu amigo por la misma razón. Pero esta vez le dices que tienes prisa y él debería Llámame. en tu teléfono móvil. Cuelga, deja la casa y haz lo que quieras hacer. Una vez que tu amigo te llame, estás tratando con la información que te dio.

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

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

    En lugar de esperar la respuesta, la ejecución continúa inmediatamente y la declaración después de la llamada Ajax se ejecuta. Para obtener la respuesta eventualmente, usted proporciona una función a llamar una vez recibida la respuesta, a callback (conozca algo? Vuelve. ?). Cualquier declaración después de que esa llamada sea ejecutada antes de que se llame el callback.


    Solución(s)

    Abrace la naturaleza asincrónica de JavaScript! Aunque ciertas operaciones asincrónicas proporcionan contrapartes sincronizadas (también "Ajax"), generalmente se desalienta utilizarlas, especialmente en un contexto del navegador.

    ¿Por qué es malo preguntar?

    JavaScript se ejecuta en el hilo UI del navegador y cualquier proceso de larga duración 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 debe continuar la ejecución o no.

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

    En lo siguiente vamos a ver tres soluciones diferentes que están construyendo una sobre otra:

    • Promesas con async/await (ES2017+, disponible en navegadores antiguos si utiliza un transpilador o regenerador)
    • Callbacks (popular en nodo)
    • Promesas con then() (ES2015+, disponible en navegadores antiguos si utiliza una de las muchas bibliotecas de promesa)

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


    ES2017+: Promesas con async/await

    La versión ECMAScript lanzada en 2017 apoyo a nivel de sintaxis para funciones asincrónicas. Con la ayuda de async y await, puedes escribir asincrónico en un "estilo sincronizado". El código sigue siendo asincrónico, pero es más fácil leer/entender.

    async/await se basa en las promesas: una async la función siempre vuelve una promesa. await "unwraps" una promesa y el resultado en el valor de la promesa fue resuelto con o arroja un error si la promesa fue rechazada.

    Importante: Sólo puedes usar await dentro de un async o en una función Módulo JavaScript. Alto nivel await no es compatible fuera de los módulos, por lo que puede tener que hacer un asinc IIFE (Expresión de funciones invocadas inmediatamente) para empezar una async context if not using a module.

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

    Aquí hay un ejemplo que elabora el demora función findItem() arriba:

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

    Corriente navegador y nodos soporte async/await. También puede apoyar entornos antiguos transformando su código a ES5 con la ayuda de regenerador (o herramientas que usan el regenerador, como Babel).


    Aceptar funciones callbacks

    Un callback es cuando la función 1 se pasa a funcionar 2. Función 2 puede llamar a la función 1 cuando esté lista. En el contexto de un proceso asincrónico, el callback se llamará cuando se haga el proceso asincrónico. Por lo general, el resultado se pasa al callback.

    En el ejemplo de la pregunta, usted puede hacer foo aceptar un callback y utilizarlo como success Callback. Así que...

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

    se convierte en

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

    Aquí definimos la función "inline" pero puede pasar cualquier referencia de función:

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

    foo se define como sigue:

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

    callback se referirá a la función que pasa a foo cuando lo llamamos y lo pasamos a success. I.e. once the Ajax request is successful, $.ajax llamarán callback y pasar la respuesta al callback (que se puede referir con result, ya que así es como definimos el callback).

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

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

    Es más fácil escribir código usando callbacks de lo que parece. Después de todo, JavaScript en el navegador está fuertemente impulsado por eventos (con eventos DOM). Recibir la respuesta de Ajax no es más que un evento. Las dificultades podrían surgir cuando usted tiene que trabajar con código de terceros, pero la mayoría de los problemas pueden resolverse simplemente pensando a través del flujo de aplicación.


    ES2015+: Promesas con entonces()

    El Promesa API es una nueva característica de ECMAScript 6 (ES2015), pero tiene buena soporte de navegador Ya. También hay muchas bibliotecas que implementan la API estándar de Promesas y proporcionan métodos adicionales para facilitar el uso y la composición de funciones asincrónicas (por ejemplo, Bluebird).

    Las promesas son contenedores para futuro valores. Cuando la promesa recibe el valor (es resuelta) o cuando se cancela (rechazado), notifica a todos sus "listeners" que quieren acceder a este valor.

    La ventaja sobre los callbacks simples es que te permiten decodificar tu código y son más fáciles de componer.

    Aquí hay un ejemplo 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).
      });
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    Aplicado a nuestra llamada de 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("https://jsonplaceholder.typicode.com/todos/1")
      .then(function(result) {
        console.log(result); // Code depending on result
      })
      .catch(function() {
        // An error occurred
      });
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    Describir todas las ventajas que prometen oferta está más allá del alcance de esta respuesta, pero si escribes nuevo código, deberías considerarlas seriamente. Proporcionan una gran abstracción y separación de su código.

    Más información sobre promesas: HTML5 rocks - Promesas de JavaScript.

    Nota lateral: objetos diferidos de jQuery

    Objetos diferidos son la implementación personalizada de las promesas de jQuery (antes de que se estandarizara la API de la promesa). Se comportan casi como promesas pero exponen una API ligeramente diferente.

    Cada método Ajax de jQuery ya devuelve un "objeto diferido" (realmente una promesa de un objeto diferido) que sólo puede volver de su función:

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

    Nota lateral: Promesa

    Tenga en cuenta que las promesas y los objetos diferidos son sólo contenedores para un valor futuro, no son el valor en sí mismo. Por ejemplo, supongamos que tenía 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 malinterpreta los problemas anteriores asincrónicos. Específicamente, $.ajax() no congela el código mientras comprueba la página '/password' en su servidor - envía una solicitud al servidor y mientras espera, devuelve inmediatamente un objeto diferido jQuery Ajax, no la respuesta del servidor. Eso significa que if declaración va a conseguir siempre este objeto diferido, tratarlo como true, y proceder como si el usuario está conectado. No está bien.

    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 sincronizadas "Ajax"

    Como mencioné, algunas operaciones asincrónicas tienen contrapartes sincronizadas. No propongo su uso, pero por completo, así es como harías una llamada sincronizada:

    Sin jQuery

    Si utiliza directamente un XMLHttpRequest objeto, paso false como tercer argumento .open.

    j Query

    Si usas j Query, usted puede establecer el async opción a false. Tenga en cuenta que esta opción es deprecated desde jQuery 1.8. Entonces puedes usar un success callback o acceso responseText propiedad de la jqXHR objeto:

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

    Si utiliza cualquier otro método jQuery Ajax, como $.get, $.getJSON, etc., tienes que cambiarlo a $.ajax (ya que sólo puede pasar parámetros de configuración a $.ajax).

    ¡Cuidado! No es posible hacer un sincronizado JSONP petición. JSONP por su propia naturaleza es siempre asincrónico (una razón más para no siquiera considerar esta opción).

    Respondida el Jan 08, 2013 a las 17:11 - por devdynamox

    Votos positivos: 0 | Votos negativos: 0

  • Si eres no usando jQuery en su código, esta respuesta es para usted

    Su código debe ser algo en las líneas de 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'
    

    Felix Kling hizo un buen trabajo escribir una respuesta para personas que usan jQuery para AJAX, pero he decidido proporcionar una alternativa para las personas que no lo son.

    ()Nota, para aquellos que usan el nuevo fetch API, Angular o promesas He añadido otra respuesta abajo)


    Lo que estás enfrentando

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

    El A en AJAX significa asincrónico. Esto significa que el envío de la solicitud (o más bien recibir la respuesta) se saca del flujo normal de ejecución. En su ejemplo, .send vuelve inmediatamente y la siguiente declaración, return result;, se ejecuta antes de la función que pasó como success Callback fue llamado.

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

    Aquí hay una analogía simple:

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

    (Fiddle)

    El valor de a devuelto undefined desde a=5 parte no ha ejecutado aún. 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 el código reactivamente , diciéndole a su programa qué hacer cuando se completó 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, estamos pasando getFive una acción para realizar cuando se complete, estamos diciendo nuestro código cómo reaccionar cuando un evento se complete (como nuestra llamada AJAX, o en este caso el tiempo de salida).

    El uso sería:

    getFive(onComplete);
    

    Que debe alertar "5" a la pantalla. (Fiddle).

    Soluciones posibles

    Hay básicamente dos maneras de resolver esto:

    1. Haga la llamada AJAX sincrónica (llamemos SJAX).
    2. Reestructura tu código para trabajar correctamente con callbacks.

    1. Sincrónico AJAX - ¡No lo hagas!

    En cuanto a AJAX sincronizado, ¡No lo hagas! La respuesta de Felix plantea algunos argumentos convincentes sobre por qué es una mala idea. Para resumirlo, 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 sincronizadas y asincrónicas. En general, sin embargo, las solicitudes asincrónicas deben preferirse a las solicitudes sincronizadas por razones de desempeño.

    En resumen, las solicitudes sincronizadas bloquean la ejecución del código... ...esto puede causar problemas graves...

    Si tú han tenido para hacerlo, puedes 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. Código de reestructuración

    Deje que su función acepte un callback. En el código de ejemplo foo se puede hacer para aceptar un callback. Vamos a estar diciendo nuestro código cómo reaccionar reacción cuando foo completa.

    Entonces:

    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 podríamos pasar fácilmente una referencia a una función existente, haciendo que parezca:

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

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

    Ahora, definamos el foo mismo 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();
    }
    

    (Jadeo)

    Ahora hemos hecho nuestro Foo función aceptar una acción para ejecutar cuando el AJAX completa con éxito. Podemos extender esto más adelante comprobando si el estado de respuesta no es 200 y actuando en consecuencia (crear un manejador de fallos y tal). Efectivamente está resolviendo nuestro problema.

    Si sigues teniendo dificultades para entender esto, leer la guía de inicio de AJAX en MDN.

    Respondida el Jan 08, 2013 a las 17:17 - por scriptsorcerer

    Votos positivos: 0 | Votos negativos: 0

  • XMLHtpRequest 2 (Primero, leer las respuestas de Benjamin Gruenbaum y Felix Kling)

    Si no utiliza jQuery y desea un breve XMLHttpRequest 2 que funciona en los navegadores modernos y también en los navegadores móviles, le sugiero que lo use 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. El callback se establece directamente (por lo que no hay cierres innecesarios extra).
    3. Utiliza la nueva onload (así que no tienes que comprobar por estado listo " ).
    4. Hay otras situaciones, que no recuerdo, que hacen que el XMLHttpRequest 1 se moleste.

    Hay dos maneras de obtener la respuesta de esta llamada de Ajax (tres usando el nombre del var de XMLHtpRequest):

    El más simple:

    this.response
    

    O si por alguna razón bind() el regreso 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 son siempre 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 el cambio de estado o el nombre de variable XMLHttpRequest. Eso está mal.

    Echa un vistazo Características avanzadas de XMLHtpRequest.

    Sostenía todos los navegadores *modernos. Y puedo confirmar que he estado usando este enfoque desde que se creó XMLHtpRequest 2. Nunca tuve ningún tipo de problema en ningún navegador que usé.

    ya el cambio de estado sólo es útil si quieres conseguir los encabezados en el estado 2.

    Usando el XMLHttpRequest nombre variable es otro gran error ya que usted necesita ejecutar el callback dentro de los cierres de onload/oreadystatechange, o si no lo perdió.


    Ahora si quieres algo más complejo usando POST y FormData puede ampliar 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)
    }
    

    Otra vez... es una función muy corta, pero sí # y POST.

    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 pasar un elemento de forma completa (document.getElementsByTagName('form')[0]):

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

    O establecer algunos valores personalizados:

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

    Como puedes ver, no implementé sincronización... Es algo malo.

    Habiendo dicho eso... ¿por qué no lo hacemos de la manera fácil?


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

    Controlador 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, usted tiene un controlador de error que se define estadísticamente, por lo que no compromete la función. El controlador de error también se puede utilizar para otras funciones.

    Pero para obtener realmente un error, el sólo manera es escribir una URL incorrecta en cuyo caso cada navegador lanza un error.

    Los controladores de error son tal vez útiles si establece cabeceras personalizadas, establece la respuestaTipo a blob array buffer, o lo que sea...

    Incluso si usted pasa 'POSTAPAPAPAP' como el método que no lanzará un error.

    Incluso si pasas 'fdggdgilfdghfldj' como formdata no lanzará un error.

    En el primer caso el error está dentro del displayAjax() menores this.statusText como Method not Allowed.

    En el segundo caso, simplemente funciona. Usted tiene que comprobar en el lado del servidor si pasó los datos de correo correctos.

    El dominio cruzado no se permite arroja un error automáticamente.

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

    Sólo hay this.type que se establece error.

    ¿Por qué añadir un controlador de error si no tienes ningún control sobre errores? La mayoría de los errores se devuelven dentro de esto en la función callback displayAjax().

    Así: No hay necesidad de cheques de error si usted es capaz de copiar y pegar la URL correctamente. ;)

    PS: Como la primera prueba que escribí x('x', displayAjax)..., ¿y tiene una respuesta totalmente...??? Así que revisé la carpeta donde se encuentra el HTML, y había un archivo llamado 'x.xml'. Así que incluso si olvida la extensión de su archivo XMLHttpRequest 2 lo encontrará. Lo siento.


    Leer un archivo sincrónico

    No hagas eso.

    Si quieres bloquear el navegador por un tiempo carga un grande agradable .txt archivo sincronizado.

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

    Ahora puedes hacerlo

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

    No hay otra manera de hacer esto de una manera no asincrónica. (Sí, con el bucle de Timeout... pero en serio?)

    Otro punto es... si trabajas con API o simplemente los archivos de tu propia lista o cualquier cosa que siempre uses diferentes funciones para cada solicitud...

    Sólo si tienes una página donde cargas siempre el mismo XML/JSON o lo que necesites solo una función. En ese caso, modificar un poco la función Ajax y reemplazar b con su función especial.


    Las funciones anteriores son para uso básico.

    Si quieres ampliación la función...

    Sí, puedes.

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

    Pero puedes hacer muchas cosas con XMLHttpRequest 2:

    Hice un gestor de descarga (usando rangos en ambos lados con curriculum vitae, filereader y filesystem), varios resizers de imagen convertidos usando tela, poblar bases de datos web SQL con base64images y mucho más...

    Pero en estos casos debe crear una función sólo para ese propósito... a veces necesita un bloque, buffers de array, puede establecer encabezados, anular mimetipo y hay mucho más...

    Pero la pregunta aquí es cómo devolver una respuesta Ajax... (Añadí una manera fácil.)

    Respondida el Jan 08, 2013 a las 17:24 - por codergeek24

    Votos positivos: 0 | Votos negativos: 0

  • Si estás usando promesas, esta respuesta es para ti.

    Esto significa AngularJS, jQuery (con diferido), nativo XHR's reemplazo (fetch), Ember.js, Backbone.js's salvo o cualquier Node.js biblioteca que devuelve promesas.

    Su código debe ser algo en las líneas de 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.
    

    Felix Kling hizo un buen trabajo escribir una respuesta para personas que usan jQuery con callbacks para Ajax. Tengo una respuesta para el nativo XHR. Esta respuesta es para el uso genérico de promesas ya sea en el frontend o backend.


    La cuestión fundamental

    El modelo JavaScript concurrency en el navegador y en el servidor con Node. js/io.js is asincrónico y reactiva.

    Siempre que llamas un método que devuelve una promesa, el then Los manipuladores son siempre ejecutado asincrónicamente - es decir, después el código debajo de ellos que no está en .then manejador.

    Esto significa cuando regreses. data el then manipulador que has definido aún no se ejecutó. Esto a su vez significa que el valor que estás regresando no se ha fijado al 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

    El valor de data es undefined desde data = 5 parte no ha ejecutado aún. Probablemente se ejecutará en un segundo, pero para ese momento es irrelevante para el valor devuelto.

    Ya que la operación aún no ocurrió (Ajax, llamada de servidor, I/O y temporizador) está devolviendo el valor antes de que la solicitud tenga la oportunidad de decirle a su código cuál es ese valor.

    Una posible solución a este problema es el código reactivamente, diciéndole a su programa qué hacer cuando se completó el cálculo. Las promesas permiten activamente esto siendo temporal (siempre sensible) en la naturaleza.

    Recapitulación rápida de promesas

    Una promesa es valor respecto del tiempo. Las promesas tienen estado. Empiezan como pendientes sin valor y pueden establecerse para:

    • cumplido significa que la computación completó con éxito.
    • rechazado significa que la computación falló.

    Una promesa sólo puede cambiar estados una vez después de lo cual siempre permanecerá en el mismo estado para siempre. Puedes adjuntar then manipuladores para promesas de extraer su valor y manejar errores. then controladores permiten cadena de llamadas. Las promesas son creadas por usando APIs que los devuelven. Por ejemplo, el reemplazo Ajax más moderno fetch o jQuery's $.get devolver promesas.

    Cuando llamemos .then sobre una promesa Regreso algo de él - tenemos una promesa para el valor procesado. Si devolvemos otra promesa conseguiremos cosas increíbles, pero mantengamos nuestros caballos.

    Con promesas

    Veamos cómo podemos resolver el problema anterior con promesas. Primero, vamos a demostrar nuestra comprensión de los estados de promesa desde arriba utilizando el Prometidor para crear una función de retraso:

    function delay(ms){ // Takes amount of milliseconds
        // Returns a new promise
        return new Promise(function(resolve, reject){
            setTimeout(function(){ // When the time is up,
                resolve(); // change the promise to the fulfilled state
            }, ms);
        });
    }
    

    Ahora, después de nosotros configuración convertido para usar promesas, podemos usar then para que cuente:

    function delay(ms){ // Takes amount of milliseconds
      // Returns a new promise
      return new Promise(function(resolve, reject){
        setTimeout(function(){ // When the time is up,
          resolve(); // change the promise to the fulfilled state
        }, ms);
      });
    }
    
    function getFive(){
      // We're RETURNING the promise. Remember, a promise is a wrapper over our value
      return delay(100).then(function(){ // When the promise is ready,
          return 5; // return the value 5. Promises are all about return values
      })
    }
    // We _have_ to wrap it like this in the call site, and we can't access the plain value
    getFive().then(function(five){
       document.body.innerHTML = five;
    });

    Básicamente, en lugar de devolver un valor que no podemos hacer por el modelo de concurrencia - estamos devolviendo un envoltura por un valor que podamos Maldición. con then. Es como una caja con la que puedes abrir then.

    Aplicar esto

    Esto significa lo mismo para su llamada API original, usted puede:

    function foo() {
        // RETURN the promise
        return fetch("/echo/json").then(function(response){
            return response.json(); // Process it inside the `then`
        });
    }
    
    foo().then(function(response){
        // Access the value inside the `then`
    })
    

    Así que esto funciona igual. Hemos aprendido que no podemos devolver valores de llamadas ya asincrónicas, pero podemos usar promesas y encadenarlos para realizar el procesamiento. Ahora sabemos cómo devolver la respuesta de una llamada asincrónica.

    ES2015 (ES6)

    ES6 presenta generadores que son funciones que pueden regresar en el centro y luego reanudar el punto en el que estaban. Esto es típicamente útil para secuencias, por ejemplo:

    function* foo(){ // Notice the star. This is ES6, so new browsers, Nodes.js, and io.js only
        yield 1;
        yield 2;
        while(true) yield 3;
    }
    

    Es una función que devuelve una iterator sobre la secuencia 1,2,3,3,3,3,.... que se puede calentar. Aunque esto es interesante por sí mismo y abre espacio para muchas posibilidades, hay un caso interesante en particular.

    Si la secuencia que estamos produciendo es una secuencia de acciones en lugar de números, podemos pausar la función cuando se produce una acción y esperarla antes de reanudar la función. Así que en lugar de una secuencia de números, necesitamos una secuencia de futuro valores - es decir: promesas.

    Este truco algo complicado, pero muy poderoso, vamos a escribir código asincrónico de una manera sincronizada. Hay varios "corredores" que hacen esto por ti. Escribir uno es unas pocas líneas de código, pero está más allá del alcance de esta respuesta. Voy a usar Bluebird Promise.coroutine pero hay otros envoltorios como co o Q.async.

    var foo = coroutine(function*(){
        var data = yield fetch("/echo/json"); // Notice the yield
        // The code here only executes _after_ the request is done
        return data.json(); // 'data' is defined
    });
    

    Este método devuelve una promesa misma, que podemos consumir de otros coroutines. Por ejemplo:

    var main = coroutine(function*(){
       var bar = yield foo(); // Wait our earlier coroutine. It returns a promise
       // The server call is done here, and the code below executes when done
       var baz = yield fetch("/api/users/" + bar.userid); // Depends on foo's result
       console.log(baz); // Runs after both requests are done
    });
    main();
    

    ES2016 (ES7)

    En ES7, esto se estandariza aún más. Hay varias propuestas ahora mismo, pero en todas ellas puedes await Promételo. Esto es sólo "azúcar" (sintaxis de la técnica) para la propuesta ES6 arriba añadiendo la async y await Palabras clave. Hacer el ejemplo anterior:

    async function foo(){
        var data = await fetch("/echo/json"); // Notice the await
        // code here only executes _after_ the request is done
        return data.json(); // 'data' is defined
    }
    

    Todavía devuelve una promesa igual:)

    Respondida el Jan 08, 2013 a las 17:29 - por techwizkid

    Votos positivos: 0 | Votos negativos: 0

  • Estás usando Ajax incorrectamente. La idea no es que devuelva nada, sino que deje los datos a algo llamado función callback, que maneja los datos.

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

    Regresar cualquier cosa en el manejador de envío no hará nada. En su lugar, debe entregar los datos, o hacer lo que quiera con él directamente dentro de la función de éxito.

    Respondida el Jan 08, 2013 a las 17:38 - por logiclinguist

    Votos positivos: 0 | Votos negativos: 0

  • Responderé con un cómic horrible y dibujado a mano. La segunda imagen es la razón por la cual result es undefined en su ejemplo de código.

    enter image description here

    Respondida el Jan 08, 2013 a las 17:47 - por quantumcoderd26d

    Votos positivos: 0 | Votos negativos: 0

  • La solución más simple es crear una función JavaScript y llamarla para el 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 a 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);
    });
    

    Respondida el Jan 08, 2013 a las 17:52 - por pixelprodigy

    Votos positivos: 0 | Votos negativos: 0

  • Angular 1

    Personas que usan AngularJS, puede manejar esta situación usando promesas.

    Aquí. dice:

    Las promesas se pueden utilizar para funciones asincrónicas no mayores y permite encadenar múltiples funciones juntas.

    Usted puede encontrar una buena explicación Aquí. también.

    Un ejemplo encontrado en documentación mencionado a continuación.

      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.
    

    Angular 2 y más tarde

    En Angular 2 con el siguiente ejemplo, pero su recomendado para utilizar observables con Angular 2.

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

    Puedes consumir eso de esta manera,

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

    Ver el original post aquí. Pero TipoScript no soporta nativo ES6 Promesas, si quieres usarlo, es posible que necesites plugin para eso.

    Además, aquí está el promesas especificación.

    Respondida el Jan 08, 2013 a las 17:57 - por scriptsculptor52b5

    Votos positivos: 0 | Votos negativos: 0

  • La mayoría de las respuestas aquí dan sugerencias útiles para cuando usted tiene una única operación asinc, pero a veces, esto surge cuando usted necesita hacer una operación asincrónica para cada uno entrada en un array u otra estructura tipo lista. La tentación es hacer esto:

    // WRONG
    var results = [];
    theArray.forEach(function(entry) {
        doSomethingAsync(entry, function(result) {
            results.push(result);
        });
    });
    console.log(results); // E.g., 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); // E.g., 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; }

    La razón por la que no funciona es que los callbacks de doSomethingAsync Aún no ha corrido para cuando intentas usar los resultados.

    Por lo tanto, si tienes un array (o lista de algún tipo) y quieres hacer operaciones asinc para cada entrada, tienes dos opciones: Hacer las operaciones en paralelo (sobrelapso), o en serie (uno tras otro en secuencia).

    Parallel

    Usted puede comenzar todos ellos y hacer un seguimiento de cuántos callbacks usted está esperando, y luego utilizar los resultados cuando usted ha conseguido que muchos callbacks:

    var results = [];
    var expecting = theArray.length;
    theArray.forEach(function(entry, index) {
        doSomethingAsync(entry, function(result) {
            results[index] = result;
            if (--expecting === 0) {
                // Done!
                console.log("Results:", results); // E.g., using the results
            }
        });
    });
    

    Ejemplo:

    var theArray = [1, 2, 3];
    var results = [];
    var expecting = theArray.length;
    theArray.forEach(function(entry, index) {
        doSomethingAsync(entry, function(result) {
            results[index] = result;
            if (--expecting === 0) {
                // Done!
                console.log("Results:", JSON.stringify(results)); // E.g., using the results
            }
        });
    });
    
    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; }

    (Nos podemos ir con expecting y sólo uso results.length === theArray.length, pero eso nos deja abiertos a la posibilidad de que theArray se cambia mientras las llamadas son sobresalientes...)

    Observe cómo utilizamos el index desde forEach para salvar el resultado en results en la misma posición a la que se refiere, incluso si los resultados llegan fuera de orden (ya que las llamadas asinc no necesariamente completan en el orden en que se iniciaron).

    Pero ¿y si necesitas Regreso los resultados de una función? Como las otras respuestas han señalado, usted no puede; usted tiene que tener su función aceptar y llamar un callback (o devolver un Promesa). Aquí hay una versión de callback:

    function doSomethingWith(theArray, callback) {
        var results = [];
        var expecting = theArray.length;
        theArray.forEach(function(entry, index) {
            doSomethingAsync(entry, function(result) {
                results[index] = result;
                if (--expecting === 0) {
                    // Done!
                    callback(results);
                }
            });
        });
    }
    doSomethingWith(theArray, function(results) {
        console.log("Results:", results);
    });
    

    Ejemplo:

    function doSomethingWith(theArray, callback) {
        var results = [];
        var expecting = theArray.length;
        theArray.forEach(function(entry, index) {
            doSomethingAsync(entry, function(result) {
                results[index] = result;
                if (--expecting === 0) {
                    // Done!
                    callback(results);
                }
            });
        });
    }
    doSomethingWith([1, 2, 3], function(results) {
        console.log("Results:", JSON.stringify(results));
    });
    
    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; }

    O aquí hay una versión devolviendo una Promise en su lugar:

    function doSomethingWith(theArray) {
        return new Promise(function(resolve) {
            var results = [];
            var expecting = theArray.length;
            theArray.forEach(function(entry, index) {
                doSomethingAsync(entry, function(result) {
                    results[index] = result;
                    if (--expecting === 0) {
                        // Done!
                        resolve(results);
                    }
                });
            });
        });
    }
    doSomethingWith(theArray).then(function(results) {
        console.log("Results:", results);
    });
    

    Por supuesto, si doSomethingAsync nos pasó errores, usaríamos reject rechazar la promesa cuando tenemos un error.)

    Ejemplo:

    function doSomethingWith(theArray) {
        return new Promise(function(resolve) {
            var results = [];
            var expecting = theArray.length;
            theArray.forEach(function(entry, index) {
                doSomethingAsync(entry, function(result) {
                    results[index] = result;
                    if (--expecting === 0) {
                        // Done!
                        resolve(results);
                    }
                });
            });
        });
    }
    doSomethingWith([1, 2, 3]).then(function(results) {
        console.log("Results:", JSON.stringify(results));
    });
    
    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; }

    (O alternativamente, usted podría hacer un envoltorio para doSomethingAsync que devuelve una promesa, y luego hace lo siguiente...)

    Si doSomethingAsync te da una Promesa, puedes usar Promise.all:

    function doSomethingWith(theArray) {
        return Promise.all(theArray.map(function(entry) {
            return doSomethingAsync(entry);
        }));
    }
    doSomethingWith(theArray).then(function(results) {
        console.log("Results:", results);
    });
    

    Si lo sabes doSomethingAsync ignorará un segundo y tercer argumento, usted puede pasar directamente a map ()map llama a su callback con tres argumentos, pero la mayoría de la gente sólo usa la primera mayoría del tiempo:

    function doSomethingWith(theArray) {
        return Promise.all(theArray.map(doSomethingAsync));
    }
    doSomethingWith(theArray).then(function(results) {
        console.log("Results:", results);
    });
    

    Ejemplo:

    function doSomethingWith(theArray) {
        return Promise.all(theArray.map(doSomethingAsync));
    }
    doSomethingWith([1, 2, 3]).then(function(results) {
        console.log("Results:", JSON.stringify(results));
    });
    
    function doSomethingAsync(value) {
        console.log("Starting async operation for " + value);
        return new Promise(function(resolve) {
            setTimeout(function() {
                console.log("Completing async operation for " + value);
                resolve(value * 2);
            }, Math.floor(Math.random() * 200));
        });
    }
    .as-console-wrapper { max-height: 100% !important; }

    Note que Promise.all resuelve su promesa con una serie de resultados de todas las promesas que usted le da cuando todos están resueltos, o rechaza su promesa cuando la primero de las promesas que le das rechaza.

    Serie

    ¿Supongo que no quieres que las operaciones estén en paralelo? Si quieres ejecutarlos uno tras otro, tienes que esperar a que cada operación se complete antes de comenzar la próxima. Aquí hay un ejemplo de una función que hace eso y llama un callback con el resultado:

    function doSomethingWith(theArray, callback) {
        var results = [];
        doOne(0);
        function doOne(index) {
            if (index < theArray.length) {
                doSomethingAsync(theArray[index], function(result) {
                    results.push(result);
                    doOne(index + 1);
                });
            } else {
                // Done!
                callback(results);
            }
        }
    }
    doSomethingWith(theArray, function(results) {
        console.log("Results:", results);
    });
    

    (Ya que estamos haciendo el trabajo en serie, podemos usar results.push(result) ya que sabemos que no conseguiremos resultados fuera de orden. En lo anterior podríamos haber usado results[index] = result;, pero en algunos de los siguientes ejemplos no tenemos un índice que usar.)

    Ejemplo:

    function doSomethingWith(theArray, callback) {
        var results = [];
        doOne(0);
        function doOne(index) {
            if (index < theArray.length) {
                doSomethingAsync(theArray[index], function(result) {
                    results.push(result);
                    doOne(index + 1);
                });
            } else {
                // Done!
                callback(results);
            }
        }
    }
    doSomethingWith([1, 2, 3], function(results) {
        console.log("Results:", JSON.stringify(results));
    });
    
    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; }

    (O, otra vez, construir un envoltorio para doSomethingAsync que te da una promesa y hacer lo siguiente...)

    Si doSomethingAsync le da una promesa, si puede utilizar ES2017+ sintaxis (tal vez con un transpilador como Babel), se puede utilizar un async función con for-of y await:

    async function doSomethingWith(theArray) {
        const results = [];
        for (const entry of theArray) {
            results.push(await doSomethingAsync(entry));
        }
        return results;
    }
    doSomethingWith(theArray).then(results => {
        console.log("Results:", results);
    });
    

    Ejemplo:

    async function doSomethingWith(theArray) {
        const results = [];
        for (const entry of theArray) {
            results.push(await doSomethingAsync(entry));
        }
        return results;
    }
    doSomethingWith([1, 2, 3]).then(function(results) {
        console.log("Results:", JSON.stringify(results));
    });
    
    function doSomethingAsync(value) {
        console.log("Starting async operation for " + value);
        return new Promise(function(resolve) {
            setTimeout(function() {
                console.log("Completing async operation for " + value);
                resolve(value * 2);
            }, Math.floor(Math.random() * 200));
        });
    }
    .as-console-wrapper { max-height: 100% !important; }

    Si no puede utilizar la sintaxis ES2017+ (sí), puede utilizar una variación en la "Promise reduce" patrón (esto es más complejo que la Promesa habitual reduce porque no estamos pasando el resultado de uno a otro, pero en lugar de reunir sus resultados en un array):

    function doSomethingWith(theArray) {
        return theArray.reduce(function(p, entry) {
            return p.then(function(results) {
                return doSomethingAsync(entry).then(function(result) {
                    results.push(result);
                    return results;
                });
            });
        }, Promise.resolve([]));
    }
    doSomethingWith(theArray).then(function(results) {
        console.log("Results:", results);
    });
    

    Ejemplo:

    function doSomethingWith(theArray) {
        return theArray.reduce(function(p, entry) {
            return p.then(function(results) {
                return doSomethingAsync(entry).then(function(result) {
                    results.push(result);
                    return results;
                });
            });
        }, Promise.resolve([]));
    }
    doSomethingWith([1, 2, 3]).then(function(results) {
        console.log("Results:", JSON.stringify(results));
    });
    
    function doSomethingAsync(value) {
        console.log("Starting async operation for " + value);
        return new Promise(function(resolve) {
            setTimeout(function() {
                console.log("Completing async operation for " + value);
                resolve(value * 2);
            }, Math.floor(Math.random() * 200));
        });
    }
    .as-console-wrapper { max-height: 100% !important; }

    ...que es menos complicado con Funciones de flecha ES2015+:

    function doSomethingWith(theArray) {
        return theArray.reduce((p, entry) => p.then(results => doSomethingAsync(entry).then(result => {
            results.push(result);
            return results;
        })), Promise.resolve([]));
    }
    doSomethingWith(theArray).then(results => {
        console.log("Results:", results);
    });
    

    Ejemplo:

    function doSomethingWith(theArray) {
        return theArray.reduce((p, entry) => p.then(results => doSomethingAsync(entry).then(result => {
            results.push(result);
            return results;
        })), Promise.resolve([]));
    }
    doSomethingWith([1, 2, 3]).then(function(results) {
        console.log("Results:", JSON.stringify(results));
    });
    
    function doSomethingAsync(value) {
        console.log("Starting async operation for " + value);
        return new Promise(function(resolve) {
            setTimeout(function() {
                console.log("Completing async operation for " + value);
                resolve(value * 2);
            }, Math.floor(Math.random() * 200));
        });
    }
    .as-console-wrapper { max-height: 100% !important; }

    Respondida el Jan 08, 2013 a las 18:05 - por stackscripter

    Votos positivos: 0 | Votos negativos: 0

  • El problema que estás experimentando se debe a la naturaleza asincrónica de las llamadas que estás realizando en las funciones. En JavaScript, las operaciones asincrónicas como las llamadas AJAX, la lectura de archivos o las promesas no bloquean la ejecución del código y por lo tanto, la función foo termina de ejecutarse antes de que se complete la llamada asincrónica.

    Para devolver el resultado de una función asincrónica, puedes usar callbacks, promesas o async/await. A continuación te muestro cómo modificar tus ejemplos para que devuelvan el resultado correctamente:

    • Ejemplo con jQuery AJAX (usando callbacks):
    javascript
    function foo(callback) {
        $.ajax({
            url: '...',
            success: function(response) {
                callback(response);
            }
        });
    }
    
    // Uso de la función foo
    foo(function(response) {
        console.log(response); // Aquí puedes trabajar con la respuesta
    });
    
    • Ejemplo utilizando Node.js (usando callback):

    ```javascript function foo(callback) { fs.readFile("path/to/file", function(err, data) { callback(data); }); }

    // Uso

    Respondida el Jan 09, 2013 a las 17:12 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Las funciones asincrónicas no pueden devolver un valor directamente porque no esperan a que se complete la operación asincrónica. En su lugar, puedes usar devoluciones de llamada, promesas o la palabra clave async/await para manejar el resultado asincrónico.

    Usando devoluciones de llamada:

    La función foo no debería devolver el valor del resultado directamente. En su lugar, debería tomar un argumento de devolución de llamada que se ejecutará cuando se complete la operación asincrónica.

    Ejemplo usando jQuery's $.ajax:

    javascript
    function foo(callback) {
        $.ajax({
            url: '...',
            success: function(response) {
                callback(response);
            }
        });
    }
    
    // Uso de la función foo
    foo(function(result) {
        // El resultado de la llamada asincrónica está disponible aquí
        console.log(result);
    });
    

    Usando promesas:

    Las promesas son objetos que representan el resultado eventual de una operación asincrónica. Puedes encadenar manipuladores .then() a una promesa para ejecutar código cuando se resuelva.

    Ejemplo usando promesas con fetch:

    javascript
    function foo() {
        return fetch(url).then(function(response) {
            return response;
        });
    }
    
    // Uso de la función foo
    foo().then(function(result) {
        // El resultado de la llamada asincrónica está disponible aquí
        console.log(result);
    });
    

    Usando async/await (solo disponible en JavaScript moderno):

    La palabra clave async/await te permite escribir código asincrónico de forma síncrona. await hace una pausa en la ejecución de la función actual hasta que se resuelva la promesa.

    Ejemplo usando async/await con fetch:

    javascript
    async function foo() {
        const response = await fetch(url);
        return response;
    }
    
    // Uso de la función foo
    foo().then(function(result) {
        // El resultado de la llamada asincrónica está disponible aquí
        console.log(result);
    });
    

    En todos estos ejemplos, el resultado de la llamada asincrónica estará disponible en el argumento callback, la promesa resuelta o la variable result después de la palabra clave await.

    Respondida el Jan 09, 2013 a las 17:25 - por Gemini

    Votos positivos: 0 | Votos negativos: 0