jQuery / .ajax() / Synchrone Anfragen und eine asynchrone Alternative
async: false in jQuery.ajax() macht eine synchrone Anfrage: Der aktuelle Ablauf wartet auf ihren Abschluss. Das kann den Hauptablauf des Browsers und die Oberfläche blockieren. Verwenden Sie für neuen Code asynchrone Anfragen und verbinden Sie Folgearbeit. Eine zweite Anfrage mit Daten der ersten erfordert keine Blockierung.
Bedeutung von async:false
Die jQuery.ajax()-API verwendet standardmäßig true. false beschleunigt nicht, sondern verhindert die Fortsetzung nach dem Aufruf bis zum Abschluss. MDNs Anleitung zu synchronen und asynchronen Anfragen erklärt die unbedienbare Oberfläche.
Bei altem synchronem Code verwenden Sie success-, error- und complete-Optionen. Seit 1.8 ist die Kombination von async:false mit jqXHR-Deferred-Verarbeitung veraltet. Das betrifft nicht alle Ajax-Aufrufe oder asynchrones .done(). .then(), .done() und .fail() gehören unten zur asynchronen Alternative.
Für Reihenfolge starten Sie die nächste Anfrage nach der ersten Antwort und geben die Anfrage zurück. Unterscheiden Sie unabhängige parallele Arbeit von abhängigen Anfragen.
Lokaler Server und vollständiger Client
Bereiten Sie Python 3, Internet und einen neuen Übungsordner vor. Speichern Sie ajax-server.py in UTF-8. Dateien und drei APIs haben denselben Ursprung. /first liefert id 7, /second verwendet parent, /slow wartet absichtlich länger für Timeout. Die Verzögerungen sind Übungsbedingungen.
from http.server import ThreadingHTTPServer, SimpleHTTPRequestHandler
from urllib.parse import urlparse, parse_qs
import json
import sys
import time
class Handler(SimpleHTTPRequestHandler):
def do_GET(self):
url = urlparse(self.path)
if url.path not in ("/first", "/second", "/slow"):
return super().do_GET()
time.sleep(2 if url.path == "/slow" else 0.4)
if url.path == "/second":
parent = parse_qs(url.query).get("parent", [""])[0]
data = {"detail": "Details for " + parent}
else:
data = {"id": 7, "name": "Alpha"}
body = json.dumps(data).encode("utf-8")
self.send_response(200)
self.send_header("Content-Type", "application/json; charset=utf-8")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
try:
self.wfile.write(body)
except (BrokenPipeError, ConnectionResetError):
pass
if __name__ == "__main__":
port = int(sys.argv[1]) if len(sys.argv) > 1 else 8000
ThreadingHTTPServer(("127.0.0.1", port), Handler).serve_forever()
Speichern Sie ajax-demo.html im selben Ordner. Nutzen Sie die offizielle Vollversion 4.0.0 statt Slim ohne Ajax. Startbuttons sind während Arbeit deaktiviert; active hält den tatsächlichen laufenden jqXHR. Die Rückgabe der zweiten Anfrage aus .then() lässt die weitere Kette auch auf diese warten.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Keep request order without blocking</title>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<style>
body { font: 16px/1.6 sans-serif; max-width: 760px; margin: 24px auto; padding: 16px; }
button { font: inherit; margin: 4px; max-width: 100%; }
pre { white-space: pre-wrap; overflow-wrap: anywhere; }
</style>
</head>
<body>
<h1>Sequence asynchronous requests</h1>
<button type="button" class="start" id="run">Run two requests</button>
<button type="button" class="start" id="error">First request fails</button>
<button type="button" class="start" id="timeout">First request times out</button>
<button type="button" id="cancel" disabled>Cancel active request</button>
<button type="button" id="reset">Reset</button>
<p id="heartbeat">heartbeat=0</p>
<pre id="result" aria-live="polite">Ready</pre>
<script>
$(function () {
let active = null, busy = false, lines = [], ticks = 0;
setInterval(function () { ticks++; $("#heartbeat").text(`heartbeat=${ticks}`); }, 100);
function log(line) { lines.push(line); $("#result").text(lines.join("\n")); }
function run(path, timeout) {
if (busy) return;
busy = true; lines = [];
$(".start, #reset").prop("disabled", true); $("#cancel").prop("disabled", false);
log("before");
active = $.ajax({ url: path, dataType: "json", timeout: timeout });
active.then(function (first) {
log("first=" + first.name);
active = $.ajax({ url: "/second", data: { parent: first.id }, dataType: "json", timeout: 1000 });
return active;
}).done(function (second) {
log("second=" + second.detail);
}).fail(function (xhr, textStatus) {
log("failed=" + textStatus + "; HTTP=" + xhr.status);
}).always(function () {
log("complete"); active = null; busy = false;
$(".start, #reset").prop("disabled", false); $("#cancel").prop("disabled", true);
});
log("returned to caller");
}
$("#run").on("click", function () { run("/first", 1000); });
$("#error").on("click", function () { run("/missing.json", 1000); });
$("#timeout").on("click", function () { run("/slow", 300); });
$("#cancel").on("click", function () { if (active) active.abort(); });
$("#reset").on("click", function () { lines = []; $("#result").text("Ready"); });
});
</script>
</body>
</html>
Anfangsausgabe; ein separater Timer erhöht heartbeat alle 100ms.
Ready
Führen Sie Folgendes im Übungsordner aus. Fehlt python, prüfen Sie Installation und Pfad. Bei belegtem 8000 verwenden Sie python ajax-server.py 8001 und passen die Adresse an.
python ajax-server.py
Öffnen Sie bei laufendem Server http://127.0.0.1:8000/ajax-demo.html statt file://. Das jQuery Content Delivery Network (CDN) benötigt Internet. Beenden Sie mit Strg+C. Geprüft wurde mit Windows Edge, 3.7.1, 4.0.0 und Python-Server; nur der Testport war ein freier anderer Port.
Reihenfolge, Fehler und Abbruch prüfen
- Run two requests zeigt zuerst before und returned to caller. heartbeat steigt während des Wartens.
- Danach folgen first=Alpha, second=Details for 7, complete. Network zeigt /second?parent=7 nach der ersten Antwort, keinen gleichzeitigen Start.
- First request fails zeigt failed=error; HTTP=404 und complete, ohne zweite Anfrage.
- First request times out begrenzt /slow mit zwei Sekunden auf 300ms: failed=timeout; HTTP=0. Null ist kein vom Server gesendeter HTTP-Code.
- Cancel active request bricht die aktive Anfrage ab: failed=abort; HTTP=0. Nach erster Antwort zeigt active auf die zweite.
- Danach sind Start und Reset wieder nutzbar. Reset setzt nur die Ausgabe auf Ready; heartbeat läuft weiter. Prüfen Sie einen normalen neuen Versuch nach Fehler.
.always() bereinigt Buttons und busy bei Erfolg und Fehler. Reine Erfolgsbereinigung könnte die Bedienung nach Fehler blockiert lassen. Unterscheiden Sie Kette und abbrechbaren jqXHR und aktualisieren Sie active je $.ajax(). Abbruch macht bereits erledigte Serverarbeit nicht rückgängig.
Alte synchrone Reihenfolge untersuchen
Führen Sie bei laufendem Server und beendeten Anfragen diesen Code einmal in der Entwicklerkonsole aus. Er erklärt altes async:false nur mit lokalem /first, nicht einer langsamen externen Adresse.
console.log("before synchronous request");
setTimeout(function () { console.log("timer after synchronous request"); }, 0);
$.ajax({
url: "/first",
dataType: "json",
async: false,
success: function (data) { console.log("success=" + data.name); },
error: function (xhr, textStatus) { console.log("failed=" + textStatus); }
});
console.log("after synchronous request");
before synchronous request
success=Alpha
after synchronous request
timer after synchronous request
success kommt vor der Zeile nach dem Aufruf, der Timer mit null Verzögerung erst nach Aufruf und Folgecode. Null Millisekunden unterbrechen keine laufende Ausführung. Eine Browserwarnung zu veralteten synchronen Anfragen zu verstecken löst die Blockierung nicht.
Loading vor einer synchronen Anfrage zu schreiben gibt möglicherweise keine ausreichende Gelegenheit zum Zeichnen, für Timer oder Eingaben. Vergleichen Sie den asynchronen heartbeat: Auf Antworten warten und den Hauptablauf blockieren sind verschiedene Dinge.
Bestehenden Code umstellen
Nur async auf true zu ändern kann eine externe Ergebnisvariable zu früh lesen. Verschieben Sie abhängige Arbeit in den Abschluss oder geben Sie Anfrage/Promise zum Warten zurück. Eine Anfrage in .then() nur zu erzeugen, ohne Rückgabe, verbindet ihre Wartezeit nicht.
Timeout, ungültige Antworten, Netzwerkfehler und Abbruch sind verschieden. Prüfen Sie in echten Anwendungen die Datenstruktur vor der Weiterverwendung. Timeout- oder Abbruchoptionen beseitigen nicht die synchrone Blockierung. Für Senden oder Speichern wählen Sie Wiederholungen passend zu möglichen doppelten Operationen.




