Dowiedz si臋, jak u偶ywa膰 AbortController w JavaScript, aby skutecznie anulowa膰 operacje asynchroniczne, takie jak 偶膮dania pobierania, timery i inne, zapewniaj膮c czystszy i wydajniejszy kod.
JavaScript AbortController: Opanowanie Anulowania Operacji Asynchronicznych
We wsp贸艂czesnym tworzeniu stron internetowych operacje asynchroniczne s膮 wszechobecne. Pobieranie danych z interfejs贸w API, ustawianie timer贸w i obs艂uga interakcji u偶ytkownika cz臋sto obejmuj膮 kod, kt贸ry dzia艂a niezale偶nie i potencjalnie przez d艂u偶szy czas. Istniej膮 jednak scenariusze, w kt贸rych nale偶y anulowa膰 te operacje przed ich zako艅czeniem. W艂a艣nie tutaj interfejs AbortController w JavaScript przychodzi z pomoc膮. Zapewnia czysty i wydajny spos贸b sygnalizowania 偶膮da艅 anulowania do operacji DOM i innych zada艅 asynchronicznych.
Zrozumienie potrzeby anulowania
Zanim zag艂臋bimy si臋 w szczeg贸艂y techniczne, zrozumiejmy, dlaczego anulowanie operacji asynchronicznych jest wa偶ne. Rozwa偶my te typowe scenariusze:
- Nawigacja u偶ytkownika: U偶ytkownik inicjuje zapytanie wyszukiwania, uruchamiaj膮c 偶膮danie API. Je艣li szybko przejdzie do innej strony, zanim 偶膮danie si臋 zako艅czy, oryginalne 偶膮danie staje si臋 nieistotne i powinno zosta膰 anulowane, aby unikn膮膰 niepotrzebnego ruchu w sieci i potencjalnych skutk贸w ubocznych.
- Zarz膮dzanie limitem czasu: Ustawiasz limit czasu dla operacji asynchronicznej. Je艣li operacja zako艅czy si臋 przed up艂ywem limitu czasu, nale偶y anulowa膰 limit czasu, aby zapobiec zb臋dnemu wykonywaniu kodu.
- Odmontowywanie komponent贸w: W frameworkach front-endowych, takich jak React lub Vue.js, komponenty cz臋sto wykonuj膮 偶膮dania asynchroniczne. Gdy komponent si臋 odmontowuje, wszelkie trwaj膮ce 偶膮dania zwi膮zane z tym komponentem powinny zosta膰 anulowane, aby unikn膮膰 wyciek贸w pami臋ci i b艂臋d贸w spowodowanych aktualizacj膮 odmontowanych komponent贸w.
- Ograniczenia zasob贸w: W 艣rodowiskach o ograniczonych zasobach (np. urz膮dzenia mobilne, systemy wbudowane) anulowanie niepotrzebnych operacji mo偶e zwolni膰 cenne zasoby i poprawi膰 wydajno艣膰. Na przyk艂ad anulowanie pobierania du偶ego obrazu, je艣li u偶ytkownik przewinie obok tej sekcji strony.
Wprowadzenie do AbortController i AbortSignal
Interfejs AbortController zosta艂 zaprojektowany w celu rozwi膮zania problemu anulowania operacji asynchronicznych. Sk艂ada si臋 z dw贸ch kluczowych komponent贸w:
- AbortController: Ten obiekt zarz膮dza sygna艂em anulowania. Ma jedn膮 metod臋,
abort(), kt贸ra s艂u偶y do sygnalizowania 偶膮dania anulowania. - AbortSignal: Ten obiekt reprezentuje sygna艂, 偶e operacja powinna zosta膰 przerwana. Jest powi膮zany z
AbortControlleri jest przekazywany do operacji asynchronicznej, kt贸ra musi by膰 anulowana.
Podstawowe u偶ycie: Anulowanie 偶膮da艅 pobierania
Zacznijmy od prostego przyk艂adu anulowania 偶膮dania fetch:
const controller = new AbortController();
const signal = controller.signal;
fetch('https://api.example.com/data', { signal })
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return response.json();
})
.then(data => {
console.log('Data:', data);
})
.catch(error => {
if (error.name === 'AbortError') {
console.log('Fetch aborted');
} else {
console.error('Fetch error:', error);
}
});
// To cancel the fetch request:
controller.abort();
Wyja艣nienie:
- Tworzymy instancj臋
AbortController. - Uzyskujemy powi膮zany
AbortSignalzcontroller. - Przekazujemy
signaldo opcjifetch. - Je艣li musimy anulowa膰 偶膮danie, wywo艂ujemy
controller.abort(). - W bloku
.catch()sprawdzamy, czy b艂膮d toAbortError. Je艣li tak, wiemy, 偶e 偶膮danie zosta艂o anulowane.
Obs艂uga AbortError
Po wywo艂aniu controller.abort(), 偶膮danie fetch zostanie odrzucone z AbortError. Wa偶ne jest, aby odpowiednio obs艂u偶y膰 ten b艂膮d w swoim kodzie. Niezastosowanie si臋 do tego mo偶e prowadzi膰 do nieobs艂u偶onych odrzucze艅 obietnic i nieoczekiwanego zachowania.
Oto bardziej solidny przyk艂ad z obs艂ug膮 b艂臋d贸w:
const controller = new AbortController();
const signal = controller.signal;
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data', { signal });
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const data = await response.json();
console.log('Data:', data);
return data;
} catch (error) {
if (error.name === 'AbortError') {
console.log('Fetch aborted');
return null; // Or throw the error to be handled further up
} else {
console.error('Fetch error:', error);
throw error; // Re-throw the error to be handled further up
}
}
}
fetchData();
// To cancel the fetch request:
controller.abort();
Najlepsze praktyki dotycz膮ce obs艂ugi AbortError:
- Sprawd藕 nazw臋 b艂臋du: Zawsze sprawdzaj, czy
error.name === 'AbortError', aby upewni膰 si臋, 偶e obs艂ugujesz w艂a艣ciwy typ b艂臋du. - Zwr贸膰 warto艣膰 domy艣ln膮 lub ponownie rzu膰: W zale偶no艣ci od logiki aplikacji mo偶esz chcie膰 zwr贸ci膰 warto艣膰 domy艣ln膮 (np.
null) lub ponownie rzuci膰 b艂膮d, aby obs艂u偶y膰 go wy偶ej w stosie wywo艂a艅. - Wyczy艣膰 zasoby: Je艣li operacja asynchroniczna przydzieli艂a jakiekolwiek zasoby (np. timery, listenery zdarze艅), wyczy艣膰 je w obs艂udze
AbortError.
Anulowanie timer贸w z AbortSignal
AbortSignal mo偶e by膰 r贸wnie偶 u偶ywany do anulowania timer贸w utworzonych za pomoc膮 setTimeout lub setInterval. Wymaga to nieco wi臋cej pracy r臋cznej, poniewa偶 wbudowane funkcje timera nie obs艂uguj膮 bezpo艣rednio AbortSignal. Musisz utworzy膰 funkcj臋 niestandardow膮, kt贸ra nas艂uchuje sygna艂u przerwania i czy艣ci timer, gdy zostanie uruchomiony.
function cancellableTimeout(callback, delay, signal) {
let timeoutId;
const timeoutPromise = new Promise((resolve, reject) => {
timeoutId = setTimeout(() => {
resolve(callback());
}, delay);
signal.addEventListener('abort', () => {
clearTimeout(timeoutId);
reject(new Error('Timeout Aborted'));
});
});
return timeoutPromise;
}
const controller = new AbortController();
const signal = controller.signal;
cancellableTimeout(() => {
console.log('Timeout executed');
}, 2000, signal)
.then(() => console.log("Timeout finished successfully"))
.catch(err => console.log(err));
// To cancel the timeout:
controller.abort();
Wyja艣nienie:
- Funkcja
cancellableTimeoutprzyjmuje wywo艂anie zwrotne, op贸藕nienie iAbortSignaljako argumenty. - Ustawia
setTimeouti przechowuje identyfikator limitu czasu. - Dodaje do
AbortSignaldetektor zdarze艅, kt贸ry nas艂uchuje zdarzeniaabort. - Gdy zdarzenie
abortzostanie uruchomione, detektor zdarze艅 czy艣ci limit czasu i odrzuca obietnic臋.
Anulowanie detektor贸w zdarze艅
Podobnie jak w przypadku timer贸w, mo偶esz u偶y膰 AbortSignal do anulowania detektor贸w zdarze艅. Jest to szczeg贸lnie przydatne, gdy chcesz usun膮膰 detektory zdarze艅 powi膮zane z komponentem, kt贸ry jest odmontowywany.
const controller = new AbortController();
const signal = controller.signal;
const button = document.getElementById('myButton');
button.addEventListener('click', () => {
console.log('Button clicked!');
}, { signal });
// To cancel the event listener:
controller.abort();
Wyja艣nienie:
- Przekazujemy
signaljako opcj臋 do metodyaddEventListener. - Gdy
controller.abort()zostanie wywo艂ane, detektor zdarze艅 zostanie automatycznie usuni臋ty.
AbortController w komponentach React
W React mo偶esz u偶y膰 AbortController do anulowania operacji asynchronicznych, gdy komponent si臋 odmontowuje. Jest to niezb臋dne, aby zapobiec wyciekom pami臋ci i b艂臋dom spowodowanym aktualizacj膮 odmontowanych komponent贸w. Oto przyk艂ad u偶ywaj膮cy haka useEffect:
import React, { useState, useEffect } from 'react';
function MyComponent() {
const [data, setData] = useState(null);
useEffect(() => {
const controller = new AbortController();
const signal = controller.signal;
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data', { signal });
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const data = await response.json();
setData(data);
} catch (error) {
if (error.name === 'AbortError') {
console.log('Fetch aborted');
} else {
console.error('Fetch error:', error);
}
}
}
fetchData();
return () => {
controller.abort(); // Cancel the fetch request when the component unmounts
};
}, []); // Empty dependency array ensures this effect runs only once on mount
return (
{data ? (
Data: {JSON.stringify(data)}
) : (
Loading...
)}
);
}
export default MyComponent;
Wyja艣nienie:
- Tworzymy
AbortControllerwewn膮trz hakauseEffect. - Przekazujemy
signaldo 偶膮daniafetch. - Zwracamy funkcj臋 czyszcz膮c膮 z haka
useEffect. Ta funkcja zostanie wywo艂ana, gdy komponent si臋 odmontowuje. - Wewn膮trz funkcji czyszcz膮cej wywo艂ujemy
controller.abort(), aby anulowa膰 偶膮danie pobierania.
Zaawansowane przypadki u偶ycia
艁a艅cuchowanie AbortSignal
Czasami mo偶esz chcie膰 po艂膮czy膰 wiele AbortSignal razem. Na przyk艂ad mo偶esz mie膰 komponent nadrz臋dny, kt贸ry musi anulowa膰 operacje w swoich komponentach podrz臋dnych. Mo偶na to osi膮gn膮膰, tworz膮c nowy AbortController i przekazuj膮c jego sygna艂 zar贸wno do komponent贸w nadrz臋dnych, jak i podrz臋dnych.
U偶ywanie AbortController z bibliotekami innych firm
Je艣li u偶ywasz biblioteki innej firmy, kt贸ra nie obs艂uguje bezpo艣rednio AbortSignal, mo偶e by膰 konieczne dostosowanie kodu do wsp贸艂pracy z mechanizmem anulowania biblioteki. Mo偶e to obejmowa膰 zawijanie asynchronicznych funkcji biblioteki we w艂asne funkcje, kt贸re obs艂uguj膮 AbortSignal.
Korzy艣ci z u偶ywania AbortController
- Poprawa wydajno艣ci: Anulowanie niepotrzebnych operacji mo偶e zmniejszy膰 ruch w sieci, wykorzystanie procesora i zu偶ycie pami臋ci, co prowadzi do poprawy wydajno艣ci, zw艂aszcza na urz膮dzeniach o ograniczonych zasobach.
- Czystszy kod:
AbortControllerzapewnia znormalizowany i elegancki spos贸b zarz膮dzania anulowaniem, dzi臋ki czemu kod jest bardziej czytelny i 艂atwiejszy w utrzymaniu. - Zapobieganie wyciekom pami臋ci: Anulowanie operacji asynchronicznych powi膮zanych z odmontowanymi komponentami zapobiega wyciekom pami臋ci i b艂臋dom spowodowanym aktualizacj膮 odmontowanych komponent贸w.
- Lepsze wra偶enia u偶ytkownika: Anulowanie nieistotnych 偶膮da艅 mo偶e poprawi膰 wra偶enia u偶ytkownika, zapobiegaj膮c wy艣wietlaniu nieaktualnych informacji i zmniejszaj膮c postrzegane op贸藕nienia.
Zgodno艣膰 przegl膮darki
AbortController jest szeroko obs艂ugiwany we wsp贸艂czesnych przegl膮darkach, w tym Chrome, Firefox, Safari i Edge. Mo偶esz sprawdzi膰 tabel臋 zgodno艣ci w dokumentach MDN Web Docs, aby uzyska膰 najnowsze informacje.
Polyfills
W przypadku starszych przegl膮darek, kt贸re natywnie nie obs艂uguj膮 AbortController, mo偶na u偶y膰 polyfill. Polyfill to fragment kodu, kt贸ry zapewnia funkcjonalno艣膰 nowszej funkcji w starszych przegl膮darkach. Istnieje kilka dost臋pnych online polyfill贸w AbortController.
Podsumowanie
Interfejs AbortController jest pot臋偶nym narz臋dziem do zarz膮dzania operacjami asynchronicznymi w JavaScript. U偶ywaj膮c AbortController, mo偶esz pisa膰 czystszy, wydajniejszy i bardziej niezawodny kod, kt贸ry elegancko obs艂uguje anulowanie. Niezale偶nie od tego, czy pobierasz dane z interfejs贸w API, ustawiasz timery, czy zarz膮dzasz detektorami zdarze艅, AbortController mo偶e pom贸c w poprawie og贸lnej jako艣ci aplikacji internetowych.