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

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

Eu adicionei uma chamada Ajax para esta function 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 function 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?

Da documentação do jQuery : você especifica a opção assíncrona para ser false para obter uma solicitação Ajax síncrona. Em seguida, seu retorno de chamada pode definir alguns dados antes que sua function mãe prossiga.

Veja como seu código ficaria se fosse alterado conforme sugerido:

 beforecreate: function (node, targetNode, type, to) { jQuery.ajax({ url: 'http://example.com/catalog/create/' + targetNode.id + '?name=' + encode(to.inp[0].value), success: function (result) { if (result.isOk == false) alert(result.message); }, async: false }); } 

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 syntax jQuery.ajax() mais elaborada.

Excelente solução! Percebi quando tentei implementá-lo que se eu retornasse um valor na cláusula success, ele voltaria indefinido. Eu tive que armazená-lo em uma variável e retornar essa variável. Este é o método que eu criei:

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

Todas essas respostas perdem o ponto de que fazer uma chamada Ajax com async: false fará com que o navegador seja interrompido até que a solicitação do Ajax seja concluída. Usar uma biblioteca de controle de stream resolverá esse problema sem desligar o navegador. Aqui está um exemplo com Frame.js :

 beforecreate: function(node,targetNode,type,to) { Frame(function(next)){ jQuery.get('http://example.com/catalog/create/', next); }); Frame(function(next, response)){ alert(response); next(); }); Frame.init(); } 
 function getURL(url){ return $.ajax({ type: "GET", url: url, cache: false, async: false }).responseText; } //example use var msg=getURL("message.php"); alert(msg); 

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 “sequenciadores de funções” como Frame.js (esta resposta )
  4. Bloquear a interface do usuário em vez de bloquear a execução (esta resposta ) (minha maneira favorita)

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 thread 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 promises 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) } 

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

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 object retornado. Note 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 object 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 function de chamada, em vez de em uma function 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 object 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 .

Este é um exemplo:

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

Primeiramente, devemos entender quando usamos $ .ajax e quando usamos $ .get / $. Post

Quando exigimos controle de baixo nível sobre o pedido de ajax, como configurações de header de solicitação, configurações de cache, configurações síncronas etc., então devemos ir para $ .ajax.

$ .get / $. post: Quando não exigimos um controle de baixo nível sobre o pedido do ajax. Simplesmente obtém / envia os dados para o servidor. É uma abreviação de

 $.ajax({ url: url, data: data, success: success, dataType: dataType }); 

e, portanto, não podemos usar outros resources (synchronization, cache etc.) com $ .get / $. post.

Portanto, para um controle de baixo nível (sync, cache, etc.) Sobre o pedido ajax, devemos usar $ .ajax

  $.ajax({ type: 'GET', url: url, data: data, success: success, dataType: dataType, async:false }); 

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

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