jQuery / .ajax() / Requêtes synchrones et alternative asynchrone
async: false dans jQuery.ajax() rend la requête synchrone : le flux actuel attend sa fin. Cela peut bloquer l’exécution principale et l’interface du navigateur. Pour le nouveau code, préférez l’asynchrone par défaut et reliez les traitements suivants. Une deuxième requête utilisant la première réponse peut rester ordonnée sans blocage.
Sens de async:false
L’API jQuery.ajax() utilise true par défaut. false n’accélère pas : il empêche le code suivant de continuer avant la fin. Le guide MDN des requêtes synchrones et asynchrones explique le manque de réactivité qui en résulte.
Dans un ancien code synchrone, utilisez les options success, error et complete. Depuis 1.8, la combinaison async:false et traitement Deferred de jqXHR est obsolète. Cela ne rend pas tout Ajax ni .done() asynchrone obsolète. Les .then(), .done() et .fail() ci-dessous appartiennent à l’alternative asynchrone.
Si le besoin est l’ordre, démarrez la suite après la première réponse et renvoyez la requête pour la relier. Distinguez travail parallèle indépendant et requête dépendant d’une valeur précédente.
Serveur local retardé et client complet
Préparez Python 3, Internet et un nouveau dossier. Enregistrez ajax-server.py en UTF-8. Fichiers et trois API ont la même origine. /first fournit id 7, /second utilise parent et /slow attend plus longtemps pour le test de délai. Ces retards sont des conditions volontaires de l’exercice.
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()
Enregistrez ajax-demo.html au même endroit. Utilisez le fichier complet officiel 4.0.0, pas slim sans Ajax. Les boutons de lancement sont désactivés pendant le travail ; active conserve le vrai jqXHR en cours. Renvoyer la seconde requête dans .then() fait attendre sa fin à la chaîne suivante.
<!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>
Sortie initiale ; un minuteur séparé augmente heartbeat toutes les 100ms.
Ready
Exécutez ceci dans le dossier. Si python manque, vérifiez installation et chemin. Si 8000 est occupé, utilisez python ajax-server.py 8001 et adaptez l’adresse.
python ajax-server.py
Ouvrez http://127.0.0.1:8000/ajax-demo.html avec le serveur actif, pas file://. Internet charge le réseau de diffusion de contenu (CDN) jQuery. Arrêtez avec Ctrl+C. L’exemple a été exécuté avec Windows Edge, 3.7.1, 4.0.0 et le serveur Python ; seul le port de vérification a été remplacé par un port libre.
Vérifier ordre, échec et annulation
- Run two requests affiche d’abord before et returned to caller. heartbeat continue pendant l’attente.
- Puis viennent first=Alpha, second=Details for 7 et complete. Network montre /second?parent=7 après la première réponse, pas un départ simultané.
- First request fails affiche failed=error; HTTP=404 puis complete. La seconde requête ne démarre pas.
- First request times out limite le retard de deux secondes de /slow à 300ms : failed=timeout; HTTP=0. Zéro n’est pas un code HTTP renvoyé par le serveur.
- Cancel active request annule la requête courante : failed=abort; HTTP=0. Après la première réponse, active désigne la seconde.
- Les boutons sont réactivés à la fin. Reset remet seulement la trace à Ready ; heartbeat continue. Vérifiez une tentative normale après un échec.
.always() restaure boutons et busy après succès ou échec. Le faire seulement au succès pourrait bloquer les commandes après erreur. Distinguez la chaîne du jqXHR annulable et actualisez active à chaque $.ajax(). Annuler côté client ne revient pas sur du travail serveur déjà effectué.
Observer l’ancien ordre synchrone
Avec le serveur actif et les autres requêtes terminées, exécutez ceci une fois dans la console. Le test explique async:false avec /first local uniquement ; ne remplacez pas l’adresse par un serveur externe lent.
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 précède la ligne après l’appel ; le minuteur de délai zéro suit l’appel synchrone et le code suivant. Zéro milliseconde n’interrompt pas l’exécution courante. Masquer un avertissement d’obsolescence du navigateur ne résout pas le blocage.
Écrire Loading avant la requête ne garantit pas au navigateur le temps de peindre, traiter minuteurs et saisies. Comparez heartbeat asynchrone pour distinguer attente d’une réponse et blocage du flux principal.
Modifier du code existant
Changer seulement async en true peut lire trop tôt une variable externe de résultat. Déplacez son utilisation dans la fin du traitement ou renvoyez requête/Promise pour permettre l’attente. Créer une requête dans .then() sans la renvoyer ne fait pas attendre la chaîne.
Délai maximal, réponse incorrecte, réseau et annulation sont distincts. Validez les données dans un programme réel. Ajouter des options d’annulation ou de délai ne supprime pas le blocage synchrone. Pour envoi ou sauvegarde, adaptez les nouvelles tentatives aux conséquences d’une opération en double.




