La búsqueda mientras se escribe tiene un error clásico: el usuario escribe cinco letras, se activan cinco solicitudes, la segunda respuesta llega la última y sus resultados anteriores sobrescriben la quinta correcta. Cada solución termina en la misma herramienta: AbortController.
let inFlight;
async function search(q) {
inFlight?.abort(); // cancel the previous query
inFlight = new AbortController();
try {
const res = await fetch(`/api/search?q=${encodeURIComponent(q)}`, {
signal: inFlight.signal,
});
render(await res.json());
} catch (err) {
if (err.name !== "AbortError") throw err; // aborts are expected
}
}
// cleanup when the component or page closes
addEventListener("pagehide", () => inFlight?.abort());Los cuatro hábitos en ese fragmento
- Un controlador en vuelo: al abortarlo también se cancela el registro de su señal, por lo que la solicitud anterior deja de consumir ancho de banda y CPU.
- AbortError es un estado normal, no un bloqueo: tráguelo, porque la solicitud cancelada hizo su trabajo al ser cancelada.
- La eliminación de rebotes todavía ayuda: la cancelación detiene el error de resultado obsoleto, la eliminación de rebotes detiene las solicitudes que eran bytes inútiles desde su nacimiento.
- Cancelar también al desmontar: la navegación y el desmontaje de componentes dejan las recuperaciones activas de lo contrario.
¿Dónde más gana sus bytes?
- Contenido con pestañas donde se recupera cada pestaña: cambiar a mitad de carga sin cancelar es la misma carrera.
- Flujos de carga de varios archivos donde el usuario debería poder cancelar un archivo, no todo el lote.
- Bucles de sondeo que se reinician: un nuevo intervalo debe retirar la solicitud anterior o llegan dos respuestas y pelean.
La página de búsqueda de este sitio intencionalmente no necesita red: el índice se envía en la página, por lo que la carrera no puede ocurrir en absoluto, lo cual es la mejor solución de todas si su conjunto de datos encaja. Cuando no es así, abortar es mejor que todo lo demás, y el código tiene quince líneas.
