Wie lasse ich jQuery warten, bis ein Ajax-Aufruf beendet ist, bevor er zurückkehrt?

243

Ich habe eine serverseitige Funktion, für die eine Anmeldung erforderlich ist. Wenn der Benutzer angemeldet ist, gibt die Funktion bei Erfolg 1 zurück. Wenn nicht, gibt die Funktion die Anmeldeseite zurück.

Ich möchte die Funktion mit Ajax und jQuery aufrufen. Ich sende die Anfrage mit einem normalen Link, auf den eine Klickfunktion angewendet wird. Wenn der Benutzer nicht angemeldet ist oder die Funktion fehlschlägt, möchte ich, dass der Ajax-Aufruf true zurückgibt, damit die href ausgelöst wird.

Wenn ich jedoch den folgenden Code verwende, wird die Funktion beendet, bevor der Ajax-Aufruf abgeschlossen ist.

Wie kann ich den Benutzer ordnungsgemäß auf die Anmeldeseite umleiten?

$(".my_link").click(
    function(){
    $.ajax({
        url: $(this).attr('href'),
        type: 'GET',
        cache: false,
        timeout: 30000,
        error: function(){
            return true;
        },
        success: function(msg){ 
            if (parseFloat(msg)){
                return false;
            } else {
                return true;
            }
        }
    });
});
Hobhouse
quelle
2
Könnte ein alter Thread sein, aber wie @kofifus darauf hinweist, ist das Setzen von async auf false ein schlechtes Design und "es werden keine Zeitüberschreitungen usw. verarbeitet". Könnte
Shan

Antworten:

355

Wenn die $.ajax()Funktion nicht sofort zurückkehren soll, setzen Sie die asyncOption auf false:

$(".my_link").click(
    function(){
    $.ajax({
        url: $(this).attr('href'),
        type: 'GET',
        async: false,
        cache: false,
        timeout: 30000,
        error: function(){
            return true;
        },
        success: function(msg){ 
            if (parseFloat(msg)){
                return false;
            } else {
                return true;
            }
        }
    });
});

Ich möchte jedoch darauf hinweisen, dass dies dem Punkt von AJAX widerspricht. Außerdem sollten Sie die Antwort in den Funktionen errorund verarbeiten success. Diese Funktionen werden nur aufgerufen, wenn die Antwort vom Server empfangen wird.

cgp
quelle
10
Die Weitergabe bewährter Verfahren ist meiner Meinung nach keine Beurteilung und das Kennzeichen einiger der besten Antworten hier auf StackOverflow.
Semperos
68
Niemals benutzen async: false. Die Ereignisschleife des Browsers bleibt hängen, während auf unzuverlässige Netzwerk-E / A gewartet wird. Es gibt immer einen besseren Weg. In diesem Fall kann das Ziel des Links die Benutzersitzung und 302 die Anmeldeseite überprüfen.
Matthew
3
Zum Testen async: falsekann sehr nützlich sein.
Jarrett
4
@ Matthew Wirklich? Was ist die Alternative zum Senden eines Ajax mit Async, bevor Benutzer an eine andere Seite gesendet oder aktualisiert werden?
NoBugs
2
asyncmit Wert falseist in den meisten Anwendungsfällen des Browsers veraltet. In neueren Versionen von Browsern kann es zu Ausnahmen kommen. Siehe xhr.spec.whatwg.org/#sync-warning (gilt für asyncParameter der xhr- openMethode, die jQuery verwendet).
Frédéric
42

Ich bin nicht mit , $.ajaxaber die $.postund $.getFunktionen, so dass , wenn ich auf die Antwort warten müssen, verwende ich diese:

$.ajaxSetup({async: false});
$.get("...");
MilMike
quelle
34

Das zugrunde liegende XMLHttpRequest-Objekt (das von jQuery zum Erstellen der Anforderung verwendet wird) unterstützt die asynchrone Eigenschaft. Setzen Sie es auf false . Mögen

async: false
idrosid
quelle
24

Anstatt async auf false zu setzen, was normalerweise ein schlechtes Design ist, sollten Sie die Benutzeroberfläche blockieren, während der Vorgang ansteht.

Dies kann mit jQuery-Versprechungen wie folgt erreicht werden:

// same as $.ajax but settings can have a maskUI property
// if settings.maskUI==true, the UI will be blocked while ajax in progress
// if settings.maskUI is other than true, it's value will be used as the color value while bloking (i.e settings.maskUI='rgba(176,176,176,0.7)'
// in addition an hourglass is displayed while ajax in progress
function ajaxMaskUI(settings) {
    function maskPageOn(color) { // color can be ie. 'rgba(176,176,176,0.7)' or 'transparent'
        var div = $('#maskPageDiv');
        if (div.length === 0) {
            $(document.body).append('<div id="maskPageDiv" style="position:fixed;width:100%;height:100%;left:0;top:0;display:none"></div>'); // create it
            div = $('#maskPageDiv');
        }
        if (div.length !== 0) {
            div[0].style.zIndex = 2147483647;
            div[0].style.backgroundColor=color;
            div[0].style.display = 'inline';
        }
    }
    function maskPageOff() {
        var div = $('#maskPageDiv');
        if (div.length !== 0) {
            div[0].style.display = 'none';
            div[0].style.zIndex = 'auto';
        }
    }
    function hourglassOn() {
        if ($('style:contains("html.hourGlass")').length < 1) $('<style>').text('html.hourGlass, html.hourGlass * { cursor: wait !important; }').appendTo('head');
        $('html').addClass('hourGlass');
    }
    function hourglassOff() {
        $('html').removeClass('hourGlass');
    }

    if (settings.maskUI===true) settings.maskUI='transparent';

    if (!!settings.maskUI) {
        maskPageOn(settings.maskUI);
        hourglassOn();
    }

    var dfd = new $.Deferred();
    $.ajax(settings)
        .fail(function(jqXHR, textStatus, errorThrown) {
            if (!!settings.maskUI) {
                maskPageOff();
                hourglassOff();
            }
            dfd.reject(jqXHR, textStatus, errorThrown);
        }).done(function(data, textStatus, jqXHR) {
            if (!!settings.maskUI) {
                maskPageOff();
                hourglassOff();
            }
            dfd.resolve(data, textStatus, jqXHR);
        });

    return dfd.promise();
}

Damit können Sie jetzt tun:

ajaxMaskUI({
    url: url,
    maskUI: true // or try for example 'rgba(176,176,176,0.7)'
}).fail(function (jqXHR, textStatus, errorThrown) {
    console.log('error ' + textStatus);
}).done(function (data, textStatus, jqXHR) {
    console.log('success ' + JSON.stringify(data));
});

Die Benutzeroberfläche wird blockiert, bis der Befehl ajax zurückgegeben wird

siehe jsfiddle

Kofifus
quelle
Tut das Festlegen von async auf false nicht genau dasselbe, außer in einer einzelnen Codezeile?
Vincent
4
Überhaupt nicht. Wenn Sie async auf false setzen, wird die Anforderung asynchronisiert. Dies bedeutet, dass die Verarbeitung angehalten wird, bis sie zurückgegeben wird. Dies ist normalerweise eine schlechte Praxis. Beispielsweise werden keine Ereignisse, andere Ajax-Anforderungen, Zeitüberschreitungen usw. verarbeitet. Sie können den obigen Code auch so ändern, dass nur ein Teil der Benutzeroberfläche blockiert wird, während Ihr Ajax verarbeitet wird (dh der Teil, auf den er sich auswirkt)
Kofifus
11

Ich denke, es wäre einfacher, wenn Sie Ihre successFunktion so codieren , dass die entsprechende Seite geladen wird, anstatt trueoder zurückzugeben false.

Anstatt zurückzukehren true, könnten Sie beispielsweise Folgendes tun:

window.location="appropriate page";

Auf diese Weise wird die Seite beim Aufrufen der Erfolgsfunktion umgeleitet.

samuelagm
quelle
5

In modernen JS können Sie einfach async/ verwenden await, wie:

  async function upload() {
    return new Promise((resolve, reject) => {
        $.ajax({
            url: $(this).attr('href'),
            type: 'GET',
            timeout: 30000,
            success: (response) => {
                resolve(response);
            },
            error: (response) => {
                reject(response);
            }
        })
    })
}

Rufen Sie es dann in einer asyncFunktion wie:

let response = await upload();
Taohidul Islam
quelle
1
Ihr Code wird nicht funktionieren ... Sie sind auf dem richtigen Weg, aber so wie es ist, wird es nicht funktionieren.
ppetree
Können Sie bitte näher darauf eingehen? Nach dem Testen des Codes, den ich auf diese Frage beantwortet habe, sollte es funktionieren.
Taohidul Islam
wait kann nicht außerhalb der asynchronen Funktion verwendet werden, es wird ein Fehler ausgegeben.
ppetree
Ja, ich habe es in der vorletzten Zeile meiner Antwort erwähnt: "Dann rufe es in einer asyncFunktion auf".
Taohidul Islam
Es ist eine großartige Lösung, aber um anderen bei der Suche nach einer großartigen Lösung zu helfen (wie ich), sollten Sie Ihren Code bearbeiten und ihn vollständiger anzeigen. Vielleicht sogar einen Link zu einer Geige. Das wäre super!
ppetree
0

Da ich es hier nicht erwähnt sehe, dachte ich, ich würde auch darauf hinweisen, dass die jQuery when- Anweisung für diesen Zweck sehr nützlich sein kann.

Ihr Beispiel sieht so aus:

$.when( $.ajax( "test.aspx" ) ).then(function( data, textStatus, jqXHR ) {
  alert( jqXHR.status ); // Alerts 200
});

Der "dann" -Teil wird erst ausgeführt, wenn der "wann" -Teil beendet ist.

Frank Hoffman
quelle
0

Es sollte warten, bis die Anfrage abgeschlossen ist. Danach werde ich get request text zurückgeben, von wo aus die Funktion aufgerufen wird.

function foo() {
    var jqXHR = $.ajax({
        url: url,
        type: 'GET',
        async: false,
    });
    return JSON.parse(jqXHR.responseText);  
}
Hassan Ejaz
quelle
Bitte erläutern Sie Ihre Lösung.
Ausfall
1
@Dropout hinzugefügt.
Hassan Ejaz
Danke @Hassan Ejaz! Antworten, die keine Erklärung haben und nur Code sind, werden als geringer Aufwand gekennzeichnet.
Aussteiger