Cancelación Asíncrona con AbortController
Al desarrollar aplicaciones web interactivas, frecuentemente necesitamos cancelar operaciones asíncronas en curso (por ejemplo, si el usuario navega a otra pantalla antes de que termine una descarga, si escribe rápido en una barra de búsqueda para descartar peticiones previas o si se excede un tiempo límite de espera).
AbortController y AbortSignal proporcionan el estándar universal de JavaScript y la plataforma web para cancelar peticiones fetch, flujos asíncronos y manejadores de eventos.
1. Cancelar Peticiones fetch() #
Un objeto AbortController expone una señal (controller.signal) que se pasa a la configuración de fetch. Al invocar controller.abort(), la petición HTTP se interrumpe inmediatamente y la promesa se rechaza con un DOMException de tipo AbortError:
1const controller = new AbortController(); 2const signal = controller.signal; 3 4fetch("https://api.servidor.com/datos-pesados", { signal }) 5 .then(res => res.json()) 6 .then(datos => console.log("Datos recibidos:", datos)) 7 .catch(err => { 8 if (err.name === "AbortError") { 9 console.log("⚠️ Petición cancelada exitosamente por el usuario."); 10 } else { 11 console.error("Error de red:", err); 12 } 13 }); 14 15// Cancelamos la petición a los 200 milisegundos 16setTimeout(() => { 17 controller.abort(); 18}, 200);
2. Tiempos Límite Automáticos con AbortSignal.timeout() (ES2022) #
En lugar de crear manualmente un setTimeout y un controlador, puedes usar AbortSignal.timeout(ms) para establecer un tiempo límite (timeout) automático:
1async function consultarConTimeout(url, limiteMs) { 2 try { 3 const respuesta = await fetch(url, { 4 signal: AbortSignal.timeout(limiteMs), // Cancela automáticamente si supera los ms 5 }); 6 return await respuesta.json(); 7 } catch (error) { 8 if (error.name === "TimeoutError") { 9 console.error(`❌ La petición superó el tiempo límite de ${limiteMs} ms`); 10 } else { 11 console.error("Fallo general:", error); 12 } 13 } 14}
3. Combinar Múltiples Señales con AbortSignal.any() (ES2024) #
Permite cancelar una operación si cualquiera de varias señales se activa (por ejemplo, si el usuario hace clic en "Cancelar" O si se agota el tiempo límite):
1const usuarioController = new AbortController(); 2const timeoutSignal = AbortSignal.timeout(5000); // 5 segundos 3 4// Se cancela si el usuario presiona el botón O si pasan 5 segundos 5const senalCombinada = AbortSignal.any([usuarioController.signal, timeoutSignal]); 6 7fetch("https://api.servidor.com/reporte", { signal: senalCombinada }) 8 .then(r => r.json()) 9 .catch(err => console.log("Operación interrumpida:", err.name));
4. Desuscribir Event Listeners Automáticamente #
AbortSignal también permite eliminar manejadores de eventos del DOM sin tener que llamar a removeEventListener:
1const botonControl = new AbortController(); 2 3window.addEventListener("resize", () => { 4 console.log("Ventana redimensionada"); 5}, { signal: botonControl.signal }); 6 7// Cuando queramos dejar de escuchar el evento: 8botonControl.abort(); // Elimina el listener automáticamente
Resumen del tema
Conceptos clave #
AbortController: interfaz estándar para emitir señales de cancelación mediantecontroller.abort().AbortSignal: token de comunicación pasado a consumidores asíncronos (fetch, streams,addEventListener).- Manejo de Errores: capturar
err.name === 'AbortError'oTimeoutError. AbortSignal.timeout(ms): aborto automático por expiración de tiempo.AbortSignal.any([s1, s2])(ES2024): composición de múltiples condiciones de cancelación.- Eventos: desuscripción limpia de listeners con
{ signal }.
Qué debes recordar #
Usa AbortController y AbortSignal.timeout() en todas tus peticiones de red críticas para prevenir fugas de memoria y peticiones obsoletas (race conditions).