jQuery: Devuelve datos después del éxito de la llamada ajax [duplicar]


Esta pregunta ya tiene una respuesta aquí:

Tengo algo como esto, donde es una simple llamada a un script que me devuelve un valor, una cadena..

function testAjax() {
    $.ajax({
      url: "getvalue.php",  
      success: function(data) {
         return data; 
      }
   });
}

Pero si llamo a algo como esto

var output = testAjax(svar);  // output will be undefined...

Entonces, ¿cómo puedo devolver el valor? el siguiente código tampoco parece funcionar...

function testAjax() {
    $.ajax({
      url: "getvalue.php",  
      success: function(data) {

      }
   });
   return data; 
}
Author: Hakam Fostok, 2011-03-15

5 answers

La única manera de devolver los datos de la función sería hacer una llamada síncrona en lugar de una llamada asíncrona, pero eso congelaría el navegador mientras espera la respuesta.

Puede pasar una función de devolución de llamada que maneja el resultado:

function testAjax(handleData) {
  $.ajax({
    url:"getvalue.php",  
    success:function(data) {
      handleData(data); 
    }
  });
}

Llámalo así:

testAjax(function(output){
  // here you use the output
});
// Note: the call won't wait for the result,
// so it will continue with the code here while waiting.
 335
Author: Guffa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-15 19:13:39

Nota: Esta respuesta fue escrita en febrero de 2010.
Vea las actualizaciones de 2015, 2016 y 2017 en la parte inferior.

No puede devolver nada de una función que sea asíncrona. Lo que puedes devolver es una promesa . Expliqué cómo funcionan las promesas en jQuery en mis respuestas a esas preguntas:

Si pudiera explicar por qué desea devolver los datos y qué desea hacer con ellos más adelante, entonces podría darle una respuesta más específica sobre cómo hacerlo.

Generalmente, en lugar de:

function testAjax() {
  $.ajax({
    url: "getvalue.php",  
    success: function(data) {
      return data; 
    }
  });
}

Puedes escribir tu función testAjax así:

function testAjax() {
  return $.ajax({
      url: "getvalue.php"
  });
}

Entonces puedes obtener tu promesa así: {[32]]}

var promise = testAjax();

Puede almacenar su promesa, puede pasarla, puede usarla como argumento en llamadas a funciones y puedes devolverlo desde funciones, pero cuando finalmente quieras usar tus datos que son devueltos por la llamada AJAX, tienes que hacerlo así:

promise.success(function (data) {
  alert(data);
});

(Consulte las actualizaciones a continuación para obtener una sintaxis simplificada.)

Si sus datos están disponibles en este punto, esta función se invocará inmediatamente. Si no lo es, se invocará tan pronto como los datos estén disponibles.

El objetivo de hacer todo esto es que sus datos no están disponibles inmediatamente después de la llamada a $.ajax porque es asíncrono. Promises es una buena abstracción para que las funciones digan: No puedo devolverte los datos porque aún no los tengo y no quiero bloquear y hacerte esperar, así que aquí hay una promise en su lugar y podrás usarla más tarde, o simplemente dársela a otra persona y terminar con ella.

Ver esto DEMO.

ACTUALIZACIÓN (2015)

Actualmente (a partir de marzo de 2015) Las promesas de jQuery no son compatible con la especificación Promises/A+ lo que significa que pueden no cooperar muy bien con otras implementaciones Promises/A+ .

Sin embargo, jQuery Promete en la próxima versión 3.x serácompatible con la especificación Promises/A+ (gracias a Benjamin Gruenbaum por señalarlo). Actualmente (a partir de mayo de 2015) las versiones estables de jQuery son 1.x y 2.x.

Lo que expliqué anteriormente (en marzo de 2011) es un forma de usar jQuery Deferred Objects para hacer algo asíncrono que en código síncrono se lograría devolviendo un valor.

Pero una llamada a una función síncrona puede hacer dos cosas: puede devolver un valor (si puede) o lanzar una excepción (si no puede devolver un valor). Promises/A + aborda ambos casos de uso de una manera que es casi tan poderosa como el manejo de excepciones en código síncrono. La versión de jQuery maneja el equivalente de devolver un valor bien, pero el equivalente al manejo complejo de excepciones es algo problemático.

En particular, el punto del manejo de excepciones en código síncrono no es simplemente renunciar a un mensaje agradable, sino tratar de solucionar el problema y continuar la ejecución, o posiblemente replantear la misma excepción o una diferente para que otras partes del programa la manejen. En el código síncrono tienes una pila de llamadas. En llamada asíncrona no lo hace y manejo avanzado de excepciones dentro de su las promesas según lo requerido por la especificación Promises/A+ realmente pueden ayudarlo a escribir código que manejará errores y excepciones de una manera significativa incluso para casos de uso complejos.

Para ver las diferencias entre jQuery y otras implementaciones, y cómo convertir jQuery promises en compatible con Promises/A+, consulte Viniendo de jQuery por Kris Kowal et al. en el wiki de la biblioteca Q y Las promesas llegan en JavaScript por Jake Archibald en HTML5 Rocks.

Cómo devolver un real promise

La función de mi ejemplo anterior:

function testAjax() {
  return $.ajax({
      url: "getvalue.php"
  });
}

Devuelve un objeto jqXHR, que es un Objeto jQuery Diferido.

Para que devuelva una promesa real, puede cambiarlo a-usando el método de la wiki Q :

function testAjax() {
  return Q($.ajax({
      url: "getvalue.php"
  }));
}

O, usando el método del artículo HTML5 Rocks :

function testAjax() {
  return Promise.resolve($.ajax({
      url: "getvalue.php"
  }));
}

Esto Promise.resolve($.ajax(...)) es también lo que se explica en la documentación del módulo promise y debería funcionar con ES6 Promise.resolve().

Para usar las promesas ES6 hoy puedes usar los módulos es6-promisepolyfill() por Jake Archibald.

Para ver dónde puedes usar las Promesas ES6 sin el polyfill, ver: Puedo usar: Promises.

Para más información véase:

Futuro de jQuery

Futuras versiones de jQuery (a partir de 3.x - las versiones estables actuales a partir de mayo de 2015 son 1.x y 2.x) será compatible con la especificación Promises/A+ (gracias a Benjamin Gruenbaum por señalarlo en los comentarios). " Dos cambios que ya hemos decidido son la compatibilidad Promise/A+ para nuestra implementación diferida [...]" (jQuery 3.0 y el futuro del desarrollo Web). Para obtener más información, consulte: jQuery 3.0: The Next Generations de Dave Methvin y jQuery 3.0: Más interoperabilidad, menos Internet Explorer por Paul Krill.

Conversaciones interesantes

ACTUALIZACIÓN (2016)

Hay una nueva sintaxis en ECMA-262, 6a Edición, Sección 14.2 llamada flecha funciones que pueden utilizarse para simplificar aún más los ejemplos anteriores.

Usando la API de jQuery, en lugar de:

promise.success(function (data) {
  alert(data);
});

Puedes escribir:

promise.success(data => alert(data));

O usando la API Promises / A+:

promise.then(data => alert(data));

Recuerde usar siempre manejadores de rechazo ya sea con:

promise.then(data => alert(data), error => alert(error));

O con:

promise.then(data => alert(data)).catch(error => alert(error));

Vea esta respuesta para ver por qué siempre debe usar manejadores de rechazo con promesas:{[32]]}

Por supuesto, en este ejemplo podrías usar solo promise.then(alert) porque solo estás llamando a alert con los mismos argumentos que tu devolución de llamada, pero la sintaxis de flecha es más general y te permite escribir cosas como:

promise.then(data => alert("x is " + data.x));

Todavía no todos los navegadores admiten esta sintaxis, pero hay ciertos casos en los que está seguro de en qué navegador se ejecutará su código, por ejemplo, al escribir una extensión Chrome , un complemento Firefox, o una aplicación de escritorio Electrón, NO.js o AppJS (ver esta respuesta para más detalles).

Para el soporte de las funciones de flecha, ver:

ACTUALIZACIÓN (2017)

Hay una sintaxis aún más nueva en este momento llamada funciones asincrónicas con una nueva palabra clave await que en lugar de este código:

functionReturningPromise()
    .then(data => console.log('Data:', data))
    .catch(error => console.log('Error:', error));

Le permite escribe:

try {
    let data = await functionReturningPromise();
    console.log('Data:', data);
} catch (error) {
    console.log('Error:', error);
}

Solo se puede utilizar dentro de una función creada con la palabra clave async. Para más información, ver:

Para soporte en navegadores, ver:

Para soporte en Nodo, ver:

En lugares donde no tienes soporte nativo para async y await puedes usar Babel:

O con una sintaxis ligeramente diferente un enfoque basado en generador como en co o Bluebird corrutinas:

Más información

Algunas otras preguntas sobre promesas para más detalles:

 361
Author: rsp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:47:25

Puede agregar la opción async a false y return fuera de la llamada ajax.

function testAjax() {
    var result="";
    $.ajax({
      url:"getvalue.php",
      async: false,  
      success:function(data) {
         result = data; 
      }
   });
   return result;
}
 161
Author: Ging3r,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-10 07:40:03

Idk si lo habéis resuelto pero os recomiendo otra forma de hacerlo, y funciona:)

    ServiceUtil = ig.Class.extend({
        base_url : 'someurl',

        sendRequest: function(request)
        {
            var url = this.base_url + request;
            var requestVar = new XMLHttpRequest();
            dataGet = false;

            $.ajax({
                url: url,
                async: false,
                type: "get",
                success: function(data){
                    ServiceUtil.objDataReturned = data;
                }
            });
            return ServiceUtil.objDataReturned;                
        }
    })

Así que la idea principal aquí es que, al agregar async: false, entonces haces que todo espere hasta que se recuperen los datos. Luego lo asignas a una variable estática de la clase, y todo funciona mágicamente:)

 -1
Author: user1509803,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-01 08:30:33

Ver ejemplo de jquery docs: http://api.jquery.com/jQuery.ajax / (alrededor de 2/3 de la página)

Usted puede estar buscando el siguiente código:

    $.ajax({
     url: 'ajax/test.html',
     success: function(data) {
     $('.result').html(data);
     alert('Load was performed.');
   }
});

Misma página...más abajo.

 -11
Author: Techism,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-22 10:11:40