¿De verdad sabes usar Fetch? Cancelación de peticiones con AbortController

3 min

1. Fetch API: la base de las peticiones Web modernas

La Fetch API ha sustituido al anticuado XMLHttpRequest como método estándar para realizar peticiones HTTP en el navegador. Está basada en Promises y ofrece una forma más sencilla y potente de hacer peticiones.

Sin embargo, la Fetch API no proporciona de forma predeterminada un mecanismo directo para cancelar peticiones. Esta función es muy importante en muchas situaciones:

  • Optimización del rendimiento: Cuando el usuario cambia rápidamente de página o introduce términos de búsqueda, cancelar las peticiones antiguas que ya no son necesarias ahorra ancho de banda y recursos del servidor.
  • Evitar condiciones de carrera: En un escenario de búsqueda mientras se escribe, una petición antigua puede responder más tarde que una nueva y hacer que la interfaz muestre datos obsoletos.
  • Prevenir fugas de memoria: Si un componente se desmonta antes de que termine una petición iniciada durante su ciclo de vida, intentar actualizar un componente que ya no existe puede provocar errores o fugas de memoria.

2. AbortController: una señal de cancelación de propósito general

AbortController es una API Web de propósito general que proporciona un mecanismo para abortar una o varias peticiones Web. Es independiente de la Fetch API, pero funciona perfectamente con Fetch.

La idea central de AbortController es:

  1. Crear una instancia de AbortController.
  2. Obtener un objeto AbortSignal de esa instancia.
  3. Pasar el AbortSignal a una API Web que se pueda abortar, como fetch.
  4. Cuando sea necesario cancelar, llamar al método de la instancia de AbortController, abort().

3. Combinar AbortController con Fetch

Veamos mediante un ejemplo cómo usar AbortController para cancelar una petición Fetch.

const controller = new AbortController();
const signal = controller.signal; // 获取信号对象

async function fetchDataWithCancellation(url) {
  try {
    console.log('Fetching data...');
    const response = await fetch(url, { signal }); // 将信号传递给 fetch
    const data = await response.json();
    console.log('Data received:', data);
    return data;
  } catch (error) {
    if (error.name === 'AbortError') {
      console.log('Fetch request was aborted.');
    } else {
      console.error('Fetch error:', error);
    }
  }
}

// 示例用法
const promise = fetchDataWithCancellation('https://jsonplaceholder.typicode.com/posts/1');

// 假设在 500 毫秒后,我们决定取消这个请求
setTimeout(() => {
  controller.abort(); // 调用 abort() 方法取消请求
  console.log('Request aborted by timeout.');
}, 500);

Cuando se llama a controller.abort(), la petición fetch se interrumpe inmediatamente y lanza un AbortError. Debes capturar este error en el bloque catch y comprobar error.name === 'AbortError' para distinguir una cancelación de otros errores de red.

4. Casos de uso reales

a. Búsqueda mientras se escribe (Search-as-you-type)

Cuando el usuario escribe rápidamente en un cuadro de búsqueda, cada entrada puede activar una nueva petición. Podemos cancelar la petición anterior que siga pendiente y conservar únicamente la más reciente.

let currentController = null;

document.getElementById('searchInput').addEventListener('input', (event) => {
  if (currentController) {
    currentController.abort(); // 取消上一个请求
  }
  currentController = new AbortController();
  const signal = currentController.signal;

  const query = event.target.value;
  if (query.length > 2) {
    fetchDataWithCancellation(`/api/search?q=${query}`, signal);
  }
});

b. Cancelar una petición al desmontar un componente

En frameworks como React o Vue, cancelar al desmontar un componente las peticiones pendientes que este inició ayuda a evitar fugas de memoria y actualizaciones innecesarias de la interfaz.

// React 示例
useEffect(() => {
  const controller = new AbortController();
  fetchDataWithCancellation('/api/data', controller.signal);

  return () => {
    controller.abort(); // 组件卸载时取消请求
  };
}, []);

Conclusión

AbortController es una herramienta indispensable en el desarrollo Web moderno. Proporciona un mecanismo nativo de cancelación para la Fetch API y otras operaciones asíncronas, y ayuda a los desarrolladores a crear aplicaciones más robustas, eficientes y agradables de usar. Dominar AbortController es una de las habilidades esenciales para convertirse en un excelente desarrollador frontend.