javascript - type - retornar valor ajax jquery




¿Cómo puedo hacer que jQuery realice una solicitud Ajax síncrona, en lugar de asíncrona? (9)

Tengo un widget de JavaScript que proporciona puntos de extensión estándar. Una de ellas es la función antes de beforecreate . Debe devolver false para evitar que se cree un elemento.

He añadido una llamada Ajax en esta función usando jQuery:

beforecreate: function (node, targetNode, type, to) {
  jQuery.get('http://example.com/catalog/create/' + targetNode.id + '?name=' + encode(to.inp[0].value),

  function (result) {
    if (result.isOk == false) 
        alert(result.message);
  });
}

Pero quiero evitar que mi widget cree el elemento, por lo que debería devolver false en la función madre, no en la devolución de llamada. ¿Hay alguna forma de realizar una solicitud AJAX síncrona utilizando jQuery o cualquier otra API en el navegador?


Con async: false obtienes un navegador bloqueado. Para una solución síncrona sin bloqueo, puede utilizar lo siguiente:

ES6 / ECMAScript2015

Con ES6 puedes usar un generador y la biblioteca co :

beforecreate: function (node, targetNode, type, to) {
    co(function*(){  
        let result = yield jQuery.get('http://example.com/catalog/create/' + targetNode.id + '?name=' + encode(to.inp[0].value));
        //Just use the result here
    });
}

ES7

Con ES7 puedes usar asyc await:

beforecreate: function (node, targetNode, type, to) {
    (async function(){
        let result = await jQuery.get('http://example.com/catalog/create/' + targetNode.id + '?name=' + encode(to.inp[0].value));
        //Just use the result here
    })(); 
}

Debido a que la operación síncrona de XMLHttpReponse está en desuso, se me ocurrió la siguiente solución que contiene XMLHttpRequest . Esto permite realizar consultas AJAX ordenadas mientras que todavía tiene una naturaleza similar, lo cual es muy útil para los tokens CSRF de un solo uso.

También es transparente, por lo que bibliotecas como jQuery funcionarán sin problemas.

/* wrap XMLHttpRequest for synchronous operation */
var XHRQueue = [];
var _XMLHttpRequest = XMLHttpRequest;
XMLHttpRequest = function()
{
  var xhr   = new _XMLHttpRequest();
  var _send = xhr.send;

  xhr.send = function()
  {
    /* queue the request, and if it's the first, process it */
    XHRQueue.push([this, arguments]);
    if (XHRQueue.length == 1)
      this.processQueue();
  };

  xhr.processQueue = function()
  {
    var call = XHRQueue[0];
    var xhr  = call[0];
    var args = call[1];

    /* you could also set a CSRF token header here */

    /* send the request */
    _send.apply(xhr, args);
  };

  xhr.addEventListener('load', function(e)
  {
    /* you could also retrieve a CSRF token header here */

    /* remove the completed request and if there is more, trigger the next */
    XHRQueue.shift();
    if (XHRQueue.length)
      this.processQueue();
  });

  return xhr;
};

Este es un ejemplo:

$.ajax({
  url: "test.html",
  async: false
}).done(function(data) {
   // Todo something..
}).fail(function(xhr)  {
   // Todo something..
});

Excelente solucion! Noté que cuando intenté implementarlo, si devolvía un valor en la cláusula de éxito, volvía como indefinido. Tuve que almacenarlo en una variable y devolver esa variable. Este es el método que se me ocurrió:

function getWhatever() {
  // strUrl is whatever URL you need to call
  var strUrl = "", strReturn = "";

  jQuery.ajax({
    url: strUrl,
    success: function(html) {
      strReturn = html;
    },
    async:false
  });

  return strReturn;
}

Puede poner la configuración Ajax de jQuery en modo síncrono llamando

jQuery.ajaxSetup({async:false});

Y luego realice sus llamadas Ajax usando jQuery.get( ... );

Luego solo enciéndelo de nuevo una vez

jQuery.ajaxSetup({async:true});

Supongo que funciona de la misma manera sugerida por @Adam, pero podría ser útil para alguien que quiere reconfigurar su jQuery.get() o jQuery.post() para la sintaxis más elaborada de jQuery.ajax() .


Tenga en cuenta que si está realizando una llamada Ajax entre dominios (utilizando JSONP ): no puede hacerlo de forma síncrona, jQuery ignorará el indicador async .

$.ajax({
    url: "testserver.php",
    dataType: 'jsonp', // jsonp
    async: false //IGNORED!!
});

Para llamadas JSONP usted podría usar:

  1. Ajax-call a su propio dominio, y realice la llamada de dominio cruzado del lado del servidor
  2. Cambia tu código para que funcione de forma asíncrona.
  3. Use una biblioteca de "secuenciador de funciones" como Frame.js (esta answer )
  4. Bloquea la interfaz de usuario en lugar de bloquear la ejecución (esta answer ) (mi forma favorita)

Usé la respuesta dada por Carcione y la modifiqué para usar JSON.

 function getUrlJsonSync(url){

    var jqxhr = $.ajax({
        type: "GET",
        url: url,
        dataType: 'json',
        cache: false,
        async: false
    });

    // 'async' has to be 'false' for this to work
    var response = {valid: jqxhr.statusText,  data: jqxhr.responseJSON};

    return response;
}    

function testGetUrlJsonSync()
{
    var reply = getUrlJsonSync("myurl");

    if (reply.valid == 'OK')
    {
        console.dir(reply.data);
    }
    else
    {
        alert('not valid');
    }    
}

Agregué el dataType de 'JSON' y cambié el .responseText a responseJSON .

También recuperé el estado usando la propiedad statusText del objeto devuelto. Tenga en cuenta que este es el estado de la respuesta Ajax, no si el JSON es válido.

El back-end debe devolver la respuesta en un JSON correcto (bien formado), de lo contrario el objeto devuelto no estará definido.

Hay dos aspectos a considerar cuando se responde a la pregunta original. Uno le dice a Ajax que realice sincrónicamente (configurando async: false ) y el otro está devolviendo la respuesta a través de la declaración de retorno de la función de llamada, en lugar de a una función de devolución de llamada.

También lo probé con POST y funcionó.

Cambié GET a POST y agregué datos: postdata

function postUrlJsonSync(url, postdata){

    var jqxhr = $.ajax({
        type: "POST",
        url: url,
        data: postdata,
        dataType: 'json',
        cache: false,
        async: false
    });

    // 'async' has to be 'false' for this to work
    var response = {valid: jqxhr.statusText,  data: jqxhr.responseJSON};

    return response;
}

Tenga en cuenta que el código anterior solo funciona en caso de que async sea falso . Si tuviera que configurar async: true, el objeto devuelto jqxhr no sería válido en el momento en que se devuelve la llamada AJAX, solo más tarde cuando la llamada asincrónica haya finalizado, pero eso es demasiado tarde para establecer la variable de respuesta .


esta es mi implementación simple para solicitudes ASYNC con jQuery. Espero que esto ayude a cualquiera.

var queueUrlsForRemove = [
    'http://dev-myurl.com/image/1', 
    'http://dev-myurl.com/image/2',
    'http://dev-myurl.com/image/3',
];

var queueImagesDelete = function(){

    deleteImage( queueUrlsForRemove.splice(0,1), function(){
        if (queueUrlsForRemove.length > 0) {
            queueImagesDelete();
        }
    });

}

var deleteImage = function(url, callback) {
    $.ajax({
        url: url,
        method: 'DELETE'
    }).done(function(response){
        typeof(callback) == 'function' ? callback(response) : null;
    });
}

queueImagesDelete();

function getURL(url){
    return $.ajax({
        type: "GET",
        url: url,
        cache: false,
        async: false
    }).responseText;
}


//example use
var msg=getURL("message.php");
alert(msg);




asynchronous