Come posso ottenere jQuery per eseguire una richiesta Ajax sincrona piuttosto che asincrona?


1208

Ho un widget JavaScript che fornisce punti di estensione standard. Uno di questi è la beforecreatefunzione. Dovrebbe tornare falseper impedire la creazione di un elemento.

Ho aggiunto una chiamata Ajax in questa funzione 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);
  });
}

Ma voglio impedire al mio widget di creare l'elemento, quindi dovrei tornare falsenella funzione madre, non nel callback. Esiste un modo per eseguire una richiesta AJAX sincrona utilizzando jQuery o qualsiasi altra API nel browser?


30
Il modo corretto di risolverlo sarebbe riscrivere il punto di estensione del widget usando le promesse. In questo modo sarebbe facilmente possibile impostare un'azione asincrona (come una richiesta Ajax) come beforecreate.
Kos,

3
Propongo la funzione Sajak. Abbiamo una lettera T? Sì vanna, dammi 3 T.
Cody O'Dell,

2
@Kos è perfetto. La sincronizzazione XHR non è richiesta qui
Michael Westcott,

1
Se le persone mi chiedono un consiglio all'avvio di javascript, dico: abbraccia il carattere asincrono di javascript, non provare a combatterlo.
Emmanuel Delay,

3
Questa domanda è come chiedere "come posso memorizzare le mie password utente in testo semplice?" Sicuro c'è una risposta, ma non farlo.
Vectorjohn,

Risposte:


1165

Dalla documentazione jQuery : si specifica l' opzione asincrona su false per ottenere una richiesta Ajax sincrona. Quindi il callback può impostare alcuni dati prima che la funzione madre proceda.

Ecco come sarebbe il tuo codice se modificato come suggerito:

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

97
Esattamente, è impossibile usare get (), post (), load () per le chiamate sincrone. Solo ajax () ha il parametro "asincrono", che può essere impostato su "falso".
SLA80,

39
@ SLA80 No. Dal jQuery 1.1: stackoverflow.com/questions/6849686/...
StuperUser

16
@qualidafial il mio commento è indirizzato al commento errato di SLA80; è possibile usare get (), post (), load () per le chiamate sincrone.
Stuper:

9
async false non è più supportato per jQuery> = 1.8. Fare riferimento a api.jquery.com/jQuery.ajax
ken il

22
@ken async: falseè ancora supportato in jQuery> = 1.8. La capacità di utilizzare async: falsecon jqXHR ( $.Deferred) è ciò che è stato deprecato. In altre parole, è necessario utilizzare le nuove opzioni esito positivo / errore / callback completo, anziché i metodi legacy, ad es jqXHR.done().
Ben Johnson,

255

È possibile mettere la configurazione Ajax di jQuery in modalità sincrona chiamando

jQuery.ajaxSetup({async:false});

E quindi eseguire le chiamate Ajax utilizzando jQuery.get( ... );

Quindi riaccenderlo una volta sola

jQuery.ajaxSetup({async:true});

Immagino che funzioni come suggerito da @Adam, ma potrebbe essere utile a qualcuno che vuole riconfigurare la propria jQuery.get()o jQuery.post()la jQuery.ajax()sintassi più elaborata .


56
Questa è una pessima idea, perché dovresti impostarla a livello globale? E poi essere costretto a disinserirlo dopo?
Juan Mendes,

11
Almeno, questa è la migliore cattiva idea. invece di dire: "NON ESISTE ALCUN MODO $.ajax()". ;)
Rzassar,

136

Ottima soluzione! Quando ho provato a implementarlo ho notato che se restituissi un valore nella clausola success, sarebbe tornato come indefinito. Ho dovuto memorizzarlo in una variabile e restituire quella variabile. Questo è il metodo che mi è venuto in mente:

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

16
Questo perché stavi restituendo un valore dal callback, non dal getWhatever. Quindi non hai restituito nulla, cioè undefineddal tuo getWhatever.
Razze di leggerezza in orbita l'

6
questo è assolutamente sbagliato. Non si può essere certi che una chiamata asincrona sia terminata quando si restituisce "strReturn".
Thomas Fritz,

61
Questa è una chiamata sincrona (asincrono: falso).
James in Indy,

85

Tutte queste risposte mancano il punto che fare una chiamata Ajax con asincrono: false causerà il blocco del browser fino al completamento della richiesta Ajax. L'uso di una libreria di controllo del flusso risolverà questo problema senza riagganciare il browser. Ecco un esempio con 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();
}

4
Le chiamate sincrone sono utili se si desidera mettere insieme un cablaggio di test rapido per un back-end REST e si preferisce la semplicità all'inferno di callback.
Distortum,

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


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

10
Tuttavia, potresti ottenere questo: "Synchronous XMLHttpRequest sul thread principale è deprecato a causa dei suoi effetti dannosi per l'esperienza dell'utente finale."
Hari,

5
@Hari Qual è il modo di eseguire una chiamata ajax sincrona usando jQuery senza usare il thread principale?
Jose Nobile,

7
Non vedo che questa risposta abbia qualcosa da offrire, è solo la risposta accettata racchiusa in una funzione e risposta quattro anni dopo. È una cosa negativa consigliare le persone a C + P, perché la funzione non indica ciò che fa. "Quindi getURLvs get? Perché si blocca il mio browser?" ecc.
Moopet,

27

Nota: non utilizzare a async: falsecausa di questi messaggi di avviso:

A partire da Gecko 30.0 (Firefox 30.0 / Thunderbird 30.0 / SeaMonkey 2.27), le richieste sincrone sul thread principale sono state deprecate a causa degli effetti negativi sull'esperienza utente.

Chrome ci avverte anche di questo nella console:

XMLHttpRequest sincrono sul thread principale è obsoleto a causa dei suoi effetti dannosi per l'esperienza dell'utente finale. Per ulteriori informazioni, consultare https://xhr.spec.whatwg.org/ .

Questo potrebbe spezzare la tua pagina se stai facendo qualcosa del genere poiché potrebbe smettere di funzionare ogni giorno.

Se vuoi farlo in un modo che sembra ancora sincrono ma che non si blocca, allora dovresti usare async / wait e probabilmente anche qualche ajax che si basa su promesse come la nuova API Fetch

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

Modifica Chrome sta lavorando su Non consentire la sincronizzazione di XHR nel licenziamento della pagina quando la pagina viene spostata via o chiusa dall'utente. Ciò comporta lo scaricamento anticipato, lo scaricamento, il pagehide e il cambio di visibilità.

Se questo è il vostro caso d'uso allora si potrebbe desiderare di avere uno sguardo a navigator.sendBeacon invece

È anche possibile per la pagina disabilitare la sincronizzazione req con le intestazioni http o l'attributo allow di iframe


Si noti che è necessario racchiudere la await fetch(url)chiamata in un try... catchblocco per rilevare eventuali errori asincroni.
Inostia,

4
la funzione foo è stata convertita in una promessa semplicemente usando la parola asyncall'inizio, quindi potresti anche fare solo foo().catch(...)per prenderla
Endless

Chrome ha già vietato ajax asincrono all'interno della pagina beforeunloadma ha ripristinato la modifica dopo un feedback negativo bugs.chromium.org/p/chromium/issues/detail?id=952452
Alex

26

Tieni presente che se stai eseguendo una chiamata Ajax tra domini (utilizzando JSONP ) - non puoi farlo in modo sincrono, il asyncflag verrà ignorato da jQuery.

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

Per le chiamate JSONP è possibile utilizzare:

  1. Chiama Ajax sul tuo dominio e fai la chiamata tra domini sul lato server
  2. Modifica il codice in modo che funzioni in modo asincrono
  3. Utilizzare una libreria "sequencer di funzioni" come Frame.js (questa risposta )
  4. Blocca l'interfaccia utente invece di bloccare l'esecuzione (questa risposta ) (il mio modo preferito)

12

Con async: falsete ti procuri un browser bloccato. Per una soluzione sincrona non bloccante è possibile utilizzare quanto segue:

ES6 / ECMAScript2015

Con ES6 puoi usare un generatore e la libreria 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 puoi semplicemente usare asyc wait:

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

3
Nota che puoi semplicemente passare async functionper creare beforecreate: async function(....e rimuovere la funzione asincrona auto-invocata
Daniel Krom,

12

Ho usato la risposta data da Carcione e l'ho modificata per usare 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');
    }    
}

Ho aggiunto il tipo di dati di "JSON" e ho modificato il .responseText in responseJSON .

Ho anche recuperato lo stato utilizzando la proprietà statusText dell'oggetto restituito. Si noti che questo è lo stato della risposta Ajax, non se JSON è valido.

Il back-end deve restituire la risposta nel JSON corretto (ben formato), altrimenti l'oggetto restituito non sarà definito.

Vi sono due aspetti da considerare quando si risponde alla domanda originale. Uno sta dicendo ad Ajax di eseguire in modo sincrono (impostando async: false ) e l'altro sta restituendo la risposta tramite l'istruzione return della funzione chiamante, piuttosto che in una funzione callback.

L'ho provato anche con POST e ha funzionato.

Ho cambiato GET in POST e ho aggiunto dati: 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;
}

Si noti che il codice sopra riportato funziona solo nel caso in cui asincrono sia falso . Se dovessi impostare asincrono: vero l'oggetto restituito jqxhr non sarebbe valido al momento della restituzione della chiamata AJAX, solo in seguito al termine della chiamata asincrona, ma è troppo tardi per impostare la variabile di risposta .


7

Questo è un esempio:

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

1
Qual è il punto di utilizzo async falsecon una soluzione basata sulla promessa. Questo blocca solo il browser senza alcun beneficio.
Codice finito

2
@GoneCoding ci sono situazioni in cui si desidera eseguire il codice in sequenza esatta, in quella situazione possiamo usare async false
Nikki

1
@ Nikki: non è assolutamente il modo di eseguirli in sequenza. Usa promesse asincrone (che le ajaxchiamate già ritornano) e .then()o done()(come già mostra). Il blocco del browser è un'esperienza utente molto scadente. Come ho detto async: falsein questo esempio è una completa perdita di tempo.
Codice finito

4

In primo luogo dovremmo capire quando usiamo $ .ajax e quando usiamo $ .get / $. Post

Quando abbiamo bisogno di un controllo di basso livello sulla richiesta Ajax come le impostazioni dell'intestazione della richiesta, le impostazioni di memorizzazione nella cache, le impostazioni sincrone ecc., Allora dovremmo andare per $ .ajax.

$ .get / $. post: quando non è richiesto un controllo di basso livello sulla richiesta Ajax. Solo per ottenere / pubblicare i dati sul server. È una scorciatoia di

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

e quindi non possiamo usare altre funzionalità (sincronizzazione, cache ecc.) con $ .get / $. post.

Quindi per un controllo di basso livello (sincronizzazione, cache, ecc.) Su richiesta Ajax, dovremmo andare per $ .ajax

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

2

questa è la mia semplice implementazione per richieste ASYNC con jQuery. Spero che questo aiuti chiunque.

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

2

Poiché XMLHttpReponseil funzionamento sincrono è deprecato, mi è venuta in mente la seguente soluzione che va a capo XMLHttpRequest. Ciò consente query AJAX ordinate pur essendo di natura asincrona, il che è molto utile per i token CSRF monouso.

È anche trasparente, quindi librerie come jQuery funzioneranno senza problemi.

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

-1

Poiché la domanda originale riguardava jQuery.get, vale la pena menzionare qui che (come menzionato qui ) si potrebbe usare async: falsein un $.get()ma idealmente evitarlo poiché asincrono XMLHTTPRequestè deprecato (e il browser potrebbe dare un avviso):

$.get({
  url: url,// mandatory
  data: data,
  success: success,
  dataType: dataType,
  async:false // to make it synchronous
});

1
perché questo è downvoted?
alias51

-2

Impostato asyn:falsenella richiesta Ajax per renderlo sincrono.

Ecco l'esempio di codice:

 $.ajax({
    url: 'some_url',
    type: "GET",
    async: false,
    cache: false,
    dataType: "JSON",
    data: { 
      "p1": v1, 
      "p2": v2
    },
    success: function(result) {
    }  
  }
});

Questo può rendere lo schermo non rispondente.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.