javascript - true - request using ajax




Como posso obter o jQuery para executar uma solicitação Ajax síncrona, em vez de assíncrona? (9)

Eu tenho um widget JavaScript que fornece pontos de extensão padrão. Uma delas é a função antes de beforecreate . Deve retornar false para evitar que um item seja criado.

Eu adicionei uma chamada Ajax para esta função 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);
  });
}

Mas eu quero evitar que meu widget crie o item, então devo retornar false na função mãe, não no retorno de chamada. Existe uma maneira de executar uma solicitação AJAX síncrona usando jQuery ou qualquer outra API no navegador?


Com async: false você obtém um navegador bloqueado. Para uma solução síncrona sem bloqueio, você pode usar o seguinte:

ES6 / ECMAScript2015

Com ES6 você pode usar um gerador e a 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

Com o ES7 você pode simplesmente usar o asyc:

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

Como a operação síncrona XMLHttpReponse está obsoleta, criei a seguinte solução que envolve XMLHttpRequest . Isso permite consultas AJAX ordenadas enquanto ainda é de natureza irregular, o que é muito útil para tokens CSRF de uso único.

Também é transparente para que bibliotecas como o jQuery funcionem perfeitamente.

/* 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 é um exemplo:

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

Eu usei a resposta dada por Carcione e modifiquei para usar o 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');
    }    
}

Eu adicionei o dataType de 'JSON' e mudei o .responseText para responseJSON .

Também recuperei o status usando a propriedade statusText do objeto retornado. Observe que este é o status da resposta do Ajax, não se o JSON é válido.

O back-end deve retornar a resposta no JSON correto (bem formado), caso contrário, o objeto retornado será indefinido.

Há dois aspectos a serem considerados ao responder a pergunta original. Uma delas é dizer ao Ajax para executar de forma síncrona (configurando async: false ) e a outra está retornando a resposta através da instrução de retorno da função de chamada, em vez de em uma função de retorno de chamada.

Eu também tentei com o POST e funcionou.

Mudei o GET para POST e adicionei dados: 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;
}

Note que o código acima só funciona no caso em que o async é falso . Se você definir async: true, o objeto retornado jqxhr não será válido no momento em que a chamada AJAX retornar, somente mais tarde, quando a chamada assíncrona for concluída, mas isso é tarde demais para definir a variável de resposta .


Nota: Você não deve usar async devido a isso:

A partir do Gecko 30.0 (Firefox 30.0 / Thunderbird 30.0 / SeaMonkey 2.27), os pedidos síncronos no thread principal foram preteridos devido aos efeitos negativos para a experiência do usuário.

O Chrome até avisa sobre isso no console:

O XMLHttpRequest síncrono no segmento principal é obsoleto devido a seus efeitos prejudiciais à experiência do usuário final. Para mais ajuda, verifique https://xhr.spec.whatwg.org/ .

Isso pode quebrar sua página se você estiver fazendo algo assim, pois pode parar de funcionar em qualquer dia.

Se você quiser fazer isso de uma forma que ainda pareça síncrona, mas que ainda não bloqueie, você deve usar async / wait e provavelmente também algum ajax baseado em promessas como a nova Fetch API

async function foo() {
  var res = await fetch(url)
  console.log(res.ok)
  var json = await res.json()
  console.log(json)
}

Tenha em mente que, se você estiver fazendo uma chamada Ajax entre domínios (usando JSONP ) - não é possível fazer isso de forma síncrona, o sinalizador async será ignorado pelo jQuery.

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

Para chamadas JSONP você pode usar:

  1. Ajax-ligue para o seu próprio domínio - e faça o lado do servidor de chamadas entre domínios
  2. Altere seu código para trabalhar de forma assíncrona
  3. Use uma biblioteca de "seqüenciador de funções" como Frame.js (esta answer )
  4. Bloquear a interface do usuário em vez de bloquear a execução (esta answer ) (minha maneira favorita)

Você pode colocar a configuração Ajax do jQuery no modo síncrono chamando

jQuery.ajaxSetup({async:false});

E então execute suas chamadas Ajax usando jQuery.get( ... );

Então é só ligá-lo novamente uma vez

jQuery.ajaxSetup({async:true});

Eu acho que funciona da mesma maneira sugerida por @Adam, mas pode ser útil para alguém que queira reconfigurar seus jQuery.get() ou jQuery.post() para a sintaxe jQuery.ajax() mais elaborada.


esta é minha implementação simples para solicitações ASYNC com jQuery. Espero que isso ajude alguém.

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