1322 Stimmen

Wie kann ich jQuery dazu bringen, eine synchrone und nicht eine asynchrone Ajax-Anfrage durchzuführen?

Ich habe ein JavaScript-Widget, das Standard-Erweiterungspunkte bietet. Einer von ihnen ist die beforecreate Funktion. Sie sollte zurückgeben false um zu verhindern, dass ein Artikel erstellt wird.

Ich habe einen Ajax-Aufruf in dieser Funktion mit jQuery hinzugefügt:

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

Aber ich möchte verhindern, dass mein Widget das Element erstellt, also sollte ich zurückgeben false in der Mutterfunktion, nicht im Rückruf. Gibt es eine Möglichkeit, eine synchrone AJAX-Anfrage mit jQuery oder eine andere in-Browser-API durchzuführen?

36 Stimmen

Der richtige Weg, um das zu lösen wäre, um Ihre Widget-Erweiterung Punkt Verwendung Versprechen neu zu schreiben. Auf diese Weise können Sie leicht eine asynchrone Aktion (wie eine Ajax-Anfrage) als beforecreate .

3 Stimmen

Ich schlage die Sajak-Funktion vor. Haben wir einen Buchstaben T? Ja, Vanna, gib mir 3 T's.

2 Stimmen

@Kos ist genau richtig. Sync XHR ist hier nicht erforderlich

31voto

Serge Shultz Punkte 5658

Beachten Sie, dass Sie bei einem domänenübergreifenden Ajax-Aufruf (unter Verwendung von JSONP ) - Sie no puede dies synchron tun, wird die async Flagge wird von jQuery ignoriert.

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

Für JSONP-Aufrufe können Sie verwenden:

  1. Ajax-Aufruf zu Ihrer eigenen Domain - und machen Sie den domänenübergreifenden Aufruf serverseitig
  2. Ändern Sie Ihren Code für asynchrones Arbeiten
  3. Verwenden Sie eine "Funktionssequenzer"-Bibliothek wie Frame.js (diese Antwort )
  4. Blockieren Sie die Benutzeroberfläche, anstatt die Ausführung zu blockieren (dies Antwort ) (meine Lieblingsmethode)

31voto

Endless Punkte 28715

Hinweis: Sie sollten nicht async: false aufgrund dieser Warnmeldungen:

Seit Gecko 30.0 (Firefox 30.0 / Thunderbird 30.0 / SeaMonkey 2.27) werden synchrone Anfragen auf dem Haupt-Thread wegen der negativen Auswirkungen auf das Benutzererlebnis nicht mehr unterstützt.

Chrome warnt sogar in der Konsole vor diesem Problem:

Synchrone XMLHttpRequest auf dem Haupt-Thread ist wegen seiner nachteiligen Auswirkungen auf die Erfahrung des Endbenutzers veraltet. Weitere Hilfe finden Sie unter https://xhr.spec.whatwg.org/ .

Dies könnte Ihre Seite zerstören, wenn Sie so etwas tun, denn sie könnte jeden Tag aufhören zu funktionieren.

Wenn Sie es eine Art und Weise, die immer noch fühlt sich an, als ob es synchron ist, aber immer noch nicht blockieren, dann sollten Sie async/await und wahrscheinlich auch einige Ajax, die auf Versprechungen wie die neue basiert tun wollen abrufen. API

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

bearbeiten chrome arbeitet an Sync XHR beim Verlassen der Seite nicht zulassen wenn die Seite vom Benutzer verlassen oder geschlossen wird. Dazu gehören beforeunload, unload, pagehide und visibilitychange.

Wenn dies Ihr Anwendungsfall ist, dann sollten Sie einen Blick auf navigator.sendBeacon stattdessen

Es ist auch möglich, dass die Seite sync req entweder mit http-Headern oder dem allow-Attribut von iframe deaktiviert wird

18voto

paulo62 Punkte 2471

Ich habe die Antwort von Carcione verwendet und sie so geändert, dass sie JSON verwendet.

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

Ich habe die dataType de JSON'. und änderte die .responseText a responseJSON .

Ich habe den Status auch mit der Funktion statusText Eigenschaft des zurückgegebenen Objekts. Beachten Sie, dass es sich hierbei um den Status der Ajax-Antwort handelt, nicht darum, ob das JSON gültig ist.

Das Back-End muss die Antwort in korrektem (wohlgeformtem) JSON zurückgeben, andernfalls ist das zurückgegebene Objekt undefiniert.

Bei der Beantwortung der ursprünglichen Frage sind zwei Aspekte zu berücksichtigen. Der eine ist die Anweisung an Ajax, synchron zu arbeiten (durch Setzen von asynchron: falsch ) und die andere ist die Rückgabe der Antwort über die Return-Anweisung der aufrufenden Funktion, anstatt in eine Callback-Funktion.

Ich habe es auch mit POST versucht und es hat funktioniert.

Ich habe GET in POST geändert und Folgendes hinzugefügt Daten: 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;
}

Beachten Sie, dass der obige Code nur in dem Fall funktioniert, wenn asynchron es falsch . Wenn Sie Folgendes einstellen würden asynchron: wahr das zurückgegebene Objekt jqxhr wäre zum Zeitpunkt der Rückkehr des AJAX-Aufrufs nicht gültig, sondern erst später, wenn der asynchrone Aufruf beendet ist, aber das ist viel zu spät, um die Antwort variabel.

14voto

Spenhouet Punkte 5261

Mit async: false besorgen Sie sich einen blockierten Browser. Für eine nicht blockierende synchrone Lösung können Sie das Folgende verwenden:

ES6/ECMAScript2015

Mit ES6 können Sie einen Generator & die Co-Bibliothek :

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

Mit ES7 können Sie einfach asyc await verwenden:

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

10voto

searching9x Punkte 1409

Dies ist ein Beispiel:

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X