Lo que quiero lograr es cancelar la solicitud anterior después de que el usuario haya cambiado los filtros.
He intentado esto:
const API_URL = "https://www.example.com" const controller = new AbortController(); const signal = controller.signal; export const fetchData = async (filters) => { // this console.log is fired only once console.log("Below I thought it would abort a request if ongoing, and ignore otherwise"); controller.abort(); const response = await fetch(`${API_URL}/products?${filters}`, { method: "GET", signal }); return await response.json(); } Pero lo que sucede es que mi solicitud se cancela incluso en la primera invocación, un poco antes de tiempo.
Otra cosa que probé es administrar AbortController así:
let controller; let signal; export const fetchData = async (filters) => { if (controller) { console.log("aborting") controller.abort(); controller = null; fetchData(filters); // won't work until I invoke this function here recursively // and I expected something like // controller = new AbortController(); // signal = controller.signal; // ... then the rest of the function would work } else { controller = new AbortController(); signal = controller.signal; } const response = await fetch(`${API_URL}/products?${filters}`, { method: "GET", signal }); console.log("fetch fulfilled") return await response.json(); } Pero el enfoque anterior no funcionaría si no incluyo la llamada recursiva de fetchData porque llamar a controller.abort() provocó que toda la función arrojara un error y no se ejecutara hasta el final, después del bloque if .
Y esto me dejaría contento si funcionara, pero la "fetch fulfilled" se cierra dos veces. ¿Por qué?
Cuando ya hay un controlador, ambos están llamando a fetchData (en la rama if ) y haciendo la búsqueda más tarde; esa rama no termina la función. Entonces terminas con dos búsquedas y dos mensajes "cumplidos".
Simplificar el código debería resolverlo (ver comentarios *** ):
let controller; // Starts out with `undefined` export const fetchData = async (filters) => { // Abort any previous request controller?.abort(); // *** Note the optional chaining controller = new AbortController(); // *** Controller for this request const response = await fetch(`${API_URL}/products?${filters}`, { method: "GET", signal: controller.signal, // *** Using this controller's signal }); console.log("fetch fulfilled"); // *** Note: You need a check `response.ok` here if (!response.ok) { throw new Error(`HTTP error ${response.status}`); } return await response.json(); };