Hasta ahora en JavaScript cuando, por ejemplo, se ha lanzado una llamada a una API con fetch, no era posible (de forma sencilla) detenerla una vez iniciada. También se puede dar el caso de que queramos detener varios elementos que se ejecutan de forma simultánea de una forma centralizada. Es por ello, que hoy vamos a hablar de la clase AbortController que viene a proporcionarnos una forma de enviar una señal de parada a todo elemento que lo utilice. Basicamente, tendremos una señal (AbortSignal) que se emitirá cuando queramos cancelar una operación.

Veamos el uso más básico, y que está en miles de ejemplos:

const abortController = new AbortController();
const abortSignal = abortController.signal;

fetch("http://myprettyurl/to/api/call, { signal: abortSignal })
    .then(function(response) {
      console.log('Respuesta obtenida', response);
    })
    .catch(function(e) {
      console.log('Algo ha fallado o lo han cancelado: ' + e.message);
    });
}

abortController.abort();

En el código anterior podemos ver como el uso de AbortController se reduce a obtener su señal, con signal, y a llamar al método abort() para lanzar la señal.

Aunque es una herramienta muy potente, no hay mucho más que explicar... bueno sí, el 99,9% de los ejemplos que podéis encontrar, son como el que he puesto en las líneas anteriores, pero, ¿y si queréis usar la clase AbortController en algo que no sea un fetch? ¿Cómo se puede escuchar el cambio en la señal? Pues a continuación he preparado un código muy sencillito. En él podéis ver como hay tres contadores avanzando, lo que haremos es detenerlos mediante una señal.

A continuación el ejemplo:

En el código, anterior, lo que hemos hecho es pasar la señal a los contadores:

const timer1 = new Timer("timer1", controller.signal);
const timer2 = new Timer("timer2", controller.signal);
const timer3 = new Timer("timer3", controller.signal);

Y para poder detectar que se ha enviado el mensaje de abortar, nada más sencillo que añadir un listener a la señal que han recibido:

this.#signal.addEventListener("abort", this.#onAbort);

De forma que en cuanto ejecutemos la llamada a abort(), entrará el código por el método #onAbort() de cada temporizador. En el ejemplo además, podéis ver como es posible pasar una cadena con un texto que luego vendrá en el atributo reason de la señal.

Como punto final imaginad que tenéis varias llamadas simultáneas a un API porque es necesario en vuestra aplicación pedir datos en paralelo. Ahora pongámonos en una situación en la que el usuario quiera cancelar la carga de datos en paralelo, por ejemplo, abrió una modal que hace las llamadas y la ha cerrado inmediatamente. Podemos detener de forma simultánea todas estas llamadas (al igual que hicimos con el ejemplo de los temporizadores):

class AnyModal {
  #abortController = new AbortController();
  #abortSignal = abortController.signal;

  openModal() {
    this.#abortController = new AbortController();
    const abortSignal = this.#abortController.signal;

    // Estas llamadas podrían estar agrupadas en un Promise.all() por ejemplo, pero por simplicidad
    // para entender la idea, las he dejado consecutivas.
    fetch("http://myprettyurl/to/api/call/1", { signal: abortSignal })...;
    fetch("http://myprettyurl/to/api/call/2", { signal: abortSignal })...;
    fetch("http://myprettyurl/to/api/call/3", { signal: abortSignal })...;

    // ...
    // Si terminan todas las llamadas podemos "deshacernos" del controller.
    this.#abortController = null;
  }

  closeModal() {
    if (this.#abortController) {
      this.#abortController.abort();
    }
  }
}

Como habéis podido comprobar, AbortController es una herramienta muy sencilla a la par que potente, y que nos puede dar muchos más usos de los que he comentado aquí. Como siempre, espero que este breve artículo os haya servido de ayuda.

Comparte este artículo con quien quieras
Aprendiendo a usar JavaScript Proxy
Decorator para novatos

Leave a Comment

Your email address will not be published. Required fields are marked *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.