web-dev-qa-db-de.com

Wie kann ich jQuery dazu bringen, eine synchrone statt eine asynchrone Ajax-Anforderung auszuführen?

Ich habe ein JavaScript-Widget, das Standard-Erweiterungspunkte bereitstellt. Eine davon ist die Funktion beforecreate. Es sollte false zurückgeben, um zu verhindern, dass ein Element erstellt wird.

Ich habe einen Ajax-Aufruf mit jQuery in diese Funktion eingefü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);
  });
}

Ich möchte jedoch verhindern, dass mein Widget das Element erstellt, daher sollte ich false in der Mutterfunktion zurückgeben, nicht im Rückruf. Gibt es eine Möglichkeit, eine synchrone AJAX -Anforderung mithilfe von jQuery oder einer anderen In-Browser-API auszuführen?

1161

Aus der jQuery-Dokumentation : Sie geben die asynchrone Option als falsch an, um eine synchrone Ajax-Anfrage zu erhalten . Dann kann Ihr Rückruf einige Daten einstellen, bevor Ihre Mutterfunktion fortgesetzt wird.

So würde Ihr Code aussehen, wenn er wie vorgeschlagen geändert würde:

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
    });
}
1120
Adam Bellaire

Sie können das Ajax-Setup der jQuery durch Aufrufen in den synchronen Modus versetzen

jQuery.ajaxSetup({async:false});

Und dann führen Sie Ihre Ajax-Anrufe mit jQuery.get( ... );

Dann einfach noch einmal einschalten

jQuery.ajaxSetup({async:true});

Ich denke, es funktioniert genauso wie von @Adam vorgeschlagen, aber es könnte für jemanden hilfreich sein, der seine jQuery.get() oder jQuery.post() auf die ausgefeiltere jQuery.ajax() -Syntax umstellen möchte.

250
Sydwell

Hervorragende Lösung! Als ich versuchte, es zu implementieren, bemerkte ich, dass ein Wert in der Erfolgsklausel als undefiniert zurückgegeben wurde. Ich musste es in einer Variablen speichern und diese Variable zurückgeben. Dies ist die Methode, die ich mir ausgedacht habe:

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;
}
133
James in Indy

Alle diese Antworten übersehen den Punkt, dass ein Ajax-Aufruf mit async: false dazu führt, dass der Browser hängt, bis die Ajax-Anforderung abgeschlossen ist. Die Verwendung einer Flusssteuerungsbibliothek löst dieses Problem, ohne dass der Browser aufhängt. Hier ist ein Beispiel mit 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();
}
83
BishopZ
function getURL(url){
    return $.ajax({
        type: "GET",
        url: url,
        cache: false,
        async: false
    }).responseText;
}


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

Beachten Sie, dass Sie bei einem domänenübergreifenden Ajax-Aufruf (mit JSONP ) - nicht tue es synchron, das async Flag 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 an Ihre eigene Domain - und den domänenübergreifenden Aufruf serverseitig durchführen
  2. Ändern Sie Ihren Code, um asynchron zu arbeiten
  3. Verwenden Sie eine "Funktionssequenzer" -Bibliothek wie Frame.js (this answer )
  4. Blockiere die Benutzeroberfläche anstatt die Ausführung zu blockieren (dies Antwort ) (meine Lieblingsmethode)
24
Serge Shultz

Hinweis: Aufgrund dieser Warnmeldungen sollten Sie async: false nicht verwenden:

Ab Gecko 30.0 (Firefox 30.0/Thunderbird 30.0/SeaMonkey 2.27) sind synchrone Anforderungen im Hauptthread aufgrund der negativen Auswirkungen auf die Benutzererfahrung veraltet.

Chrome warnt sogar in der Konsole davor:

Synchrones XMLHttpRequest für den Hauptthread wird aufgrund seiner nachteiligen Auswirkungen auf die Erfahrung des Endbenutzers nicht mehr empfohlen. Weitere Hilfe erhalten Sie unter https://xhr.spec.whatwg.org/ .

Dies könnte Ihre Seite beschädigen, wenn Sie so etwas tun, da sie jeden Tag nicht mehr funktioniert.

Wenn Sie es so machen möchten, dass es sich immer noch so anfühlt, als ob es synchron wäre, aber nicht blockiert, sollten Sie async/await und wahrscheinlich auch Ajax verwenden, das auf Versprechungen wie der neuen Fetch API basiert

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

Bearbeiten chrome arbeitet an Synchronisation von XHR bei Seitenentlassung nicht zulassen wenn die Seite weg navigiert wird oder vom Benutzer geschlossen. Dies beinhaltet vor dem Entladen, Entladen, Ausblenden und Sichtbarkeitsänderung.

wenn dies Ihr Anwendungsfall ist, sollten Sie sich stattdessen navigator.sendBeacon ansehen

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

24
Endless

Ich habe die von Carcione gegebene Antwort verwendet und sie für die Verwendung von JSON modifiziert.

 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 dataType von 'JSON' hinzugefügt und . ResponseText in responseJSON geändert.

Ich habe den Status auch über die statusText -Eigenschaft des zurückgegebenen Objekts abgerufen. Beachten Sie, dass dies der Status der Ajax-Antwort ist und nicht, ob die JSON gültig ist.

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

Bei der Beantwortung der ursprünglichen Frage sind zwei Aspekte zu berücksichtigen. Einer weist Ajax an, synchron zu arbeiten (durch Setzen von async: false), und der andere gibt die Antwort über die return-Anweisung der aufrufenden Funktion zurück und nicht in eine Rückruffunktion.

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

Ich habe das GET in POST geändert und data: postdata hinzugefügt

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, in dem asyncfalse ist. Wenn Sie async: true festlegen, ist das zurückgegebene Objekt jqxhr zum Zeitpunkt der Rückkehr des Aufrufs AJAX nicht gültig, erst später, wenn der asynchrone Aufruf erfolgt ist beendet, aber das ist viel zu spät, um die Variable response zu setzen.

11
paulo62

Mit async: false bekommen Sie einen gesperrten Browser. Für eine nicht blockierende synchrone Lösung können Sie Folgendes verwenden:

ES6/ECMAScript2015

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

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

Dies ist ein Beispiel:

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

Erstens sollten wir verstehen, wann wir $ .ajax und wann wir $ .get/$. Post verwenden

Wenn Sie die Ajax-Anforderung auf niedriger Ebene steuern möchten, z. B. Einstellungen für Anforderungsheader, Caching-Einstellungen, synchrone Einstellungen usw., sollten Sie sich für $ .ajax entscheiden.

$ .get/$ .post: Wenn keine untergeordnete Kontrolle über die Ajax-Anforderung erforderlich ist. Die Daten können nur einfach abgerufen/an den Server gesendet werden. Dies ist eine Abkürzung von

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

und daher können wir keine anderen Funktionen (Synchronisierung, Cache usw.) mit $ .get/$ .post verwenden.

Daher sollten wir für die Steuerung auf niedriger Ebene (Synchronisierung, Cache usw.) Über Ajax-Anforderungen $ .ajax verwenden

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

Da der Synchronlauf XMLHttpReponse veraltet ist, habe ich die folgende Lösung gefunden, die XMLHttpRequest umschließt. Dies ermöglicht geordnete AJAX Abfragen, während sie noch asycnron sind, was für CSRF-Token zur einmaligen Verwendung sehr nützlich ist.

Es ist auch transparent, damit Bibliotheken wie jQuery nahtlos funktionieren.

/* 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
Geoffrey

dies ist meine einfache Implementierung für ASYNC-Anfragen mit jQuery. Ich hoffe das hilft jemandem.

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();
1
Felipe Marques

Dies ist mein "Thread" Namespace:

var Thread = {
    sleep: function(ms) {
        var start = Date.now();

        while (true) {
            var clock = (Date.now() - start);
            if (clock >= ms) break;
        }

    }
};

Und so nenne ich es:

var d1 = new Date();
console.log('start ' + d1.toLocaleTimeString());
Thread.sleep(10000);
var d2 = new Date();
console.log('end ' + d2.toLocaleTimeString());

Und wenn wir auf die Konsole schauen, erhalten wir folgendes Ergebnis:

start 1:41:21 PM
end 1:41:31 PM
0
Tell Me How