jQuery / .ajax() / Peticiones síncronas y alternativa asíncrona
async: false en jQuery.ajax() hace una petición síncrona: el flujo actual espera a que termine. Puede bloquear la ejecución principal y la interfaz. Para código nuevo, prefiera el modo asíncrono predeterminado y conecte el trabajo posterior. Una segunda petición que necesita la primera respuesta puede mantener el orden sin bloquear.
Qué significa async:false
La API de jQuery.ajax() usa true por defecto. false no acelera: impide continuar después de la llamada antes de completar. La guía MDN sobre peticiones síncronas y asíncronas explica la falta de respuesta resultante.
En código síncrono antiguo use opciones success, error y complete. Desde 1.8 está obsoleta la combinación async:false con procesamiento Deferred de jqXHR. No significa que todo Ajax o .done() asíncrono esté obsoleto. Los .then(), .done() y .fail() siguientes pertenecen a la alternativa asíncrona.
Si necesita orden, inicie la siguiente petición tras la respuesta y devuélvala para conectarla. Distinga peticiones paralelas independientes de aquellas que necesitan un valor anterior.
Servidor local con demora y cliente completo
Prepare Python 3, Internet y una carpeta nueva. Guarde ajax-server.py en UTF-8. Archivos y tres API comparten origen. /first devuelve id 7, /second usa parent y /slow espera más para el tiempo límite. Las demoras son condiciones deliberadas del ejercicio.
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()
Guarde ajax-demo.html allí. Use el archivo oficial completo 4.0.0, no slim sin Ajax. Los inicios quedan deshabilitados mientras se trabaja y active guarda el jqXHR real actual. Devolver la segunda petición desde .then() hace que la cadena posterior también espere por ella.
<!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>
Salida inicial; un temporizador separado aumenta heartbeat cada 100ms.
Ready
Ejecute esto en la carpeta. Si falta python, revise instalación y ruta. Si 8000 está ocupado, use python ajax-server.py 8001 y cambie la dirección.
python ajax-server.py
Con el servidor activo, abra http://127.0.0.1:8000/ajax-demo.html, no file://. Internet carga la red de distribución de contenido (CDN) de jQuery. Detenga con Ctrl+C al acabar. Se ejecutó con Windows Edge, 3.7.1, 4.0.0 y servidor Python; solo se sustituyó el puerto de verificación por uno libre.
Verificar orden, errores y cancelación
- Run two requests muestra primero before y returned to caller. heartbeat continúa durante la espera.
- Después aparecen first=Alpha, second=Details for 7 y complete. Network muestra /second?parent=7 tras la primera respuesta, no un inicio simultáneo.
- First request fails produce failed=error; HTTP=404 y complete, sin iniciar la segunda.
- First request times out limita la demora de dos segundos de /slow a 300ms: failed=timeout; HTTP=0. Cero no es un código HTTP enviado por el servidor.
- Cancel active request cancela la petición actual: failed=abort; HTTP=0. Tras la primera respuesta, active apunta a la segunda.
- Al acabar se habilitan los controles. Reset devuelve solo la salida a Ready; heartbeat continúa. Compruebe un intento normal tras fallar.
.always() restaura controles y busy tanto en éxito como en error. Limpiar solo en éxito podría dejar botones bloqueados tras fallar. Distinga la cadena del jqXHR cancelable y actualice active por cada $.ajax(). Cancelar no deshace trabajo ya ejecutado en el servidor.
Observar el orden síncrono antiguo
Con servidor activo y otras peticiones terminadas, ejecute esto una vez en la consola. Explica async:false usando solo /first local; no lo cambie por una dirección externa lenta.
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 precede a la línea posterior; el temporizador de cero demora ejecuta después de la llamada síncrona y el código siguiente. Cero milisegundos no interrumpe el flujo actual. Ocultar la advertencia de obsolescencia no soluciona el bloqueo.
Escribir Loading antes no garantiza tiempo para dibujar ni procesar temporizadores y entradas. Compare heartbeat asíncrono para distinguir esperar una respuesta de bloquear el flujo principal.
Cambiar código existente
Cambiar solo async a true puede leer una variable externa antes de estar lista. Mueva su uso a la finalización o devuelva petición/Promise para esperar. Crear una petición dentro de .then() sin devolverla no hace que la cadena espere.
Tiempo límite, respuesta mal formada, red y cancelación son resultados distintos. Valide datos en programas reales. Añadir opciones de tiempo o cancelación no elimina el bloqueo síncrono. Para envíos o guardados, adapte reintentos a las consecuencias de repetir una operación.




