Leer hoe u JavaScript's AbortController gebruikt om asynchrone bewerkingen zoals fetch-verzoeken, timers en meer effectief te annuleren, voor schonere en betere code.
JavaScript AbortController: Asynchrone Bewerkingen Annuleren als een Pro
In moderne webontwikkeling zijn asynchrone bewerkingen alomtegenwoordig. Het ophalen van gegevens van API's, het instellen van timers en het afhandelen van gebruikersinteracties omvatten vaak code die onafhankelijk en mogelijk voor langere tijd wordt uitgevoerd. Er zijn echter scenario's waarin u deze bewerkingen moet annuleren voordat ze zijn voltooid. Dit is waar de AbortController
interface in JavaScript te hulp schiet. Het biedt een schone en efficiënte manier om annuleringsverzoeken te signaleren naar DOM-bewerkingen en andere asynchrone taken.
Het Begrijpen van de Noodzaak tot Annulering
Voordat we ingaan op de technische details, laten we begrijpen waarom het annuleren van asynchrone bewerkingen belangrijk is. Denk aan deze veelvoorkomende scenario's:
- Gebruikersnavigatie: Een gebruiker start een zoekopdracht, waardoor een API-verzoek wordt geactiveerd. Als ze snel naar een andere pagina navigeren voordat het verzoek is voltooid, wordt het oorspronkelijke verzoek irrelevant en moet het worden geannuleerd om onnodig netwerkverkeer en mogelijke neveneffecten te voorkomen.
- Timeout Management: U stelt een timeout in voor een asynchrone bewerking. Als de bewerking is voltooid voordat de timeout verloopt, moet u de timeout annuleren om redundante code-uitvoering te voorkomen.
- Component Ontkoppeling: In front-end frameworks zoals React of Vue.js doen componenten vaak asynchrone verzoeken. Wanneer een component ontkoppelt, moeten alle lopende verzoeken die aan die component zijn gekoppeld, worden geannuleerd om geheugenlekken en fouten te voorkomen die worden veroorzaakt door het bijwerken van ontkoppelde componenten.
- Resourcebeperkingen: In resource-beperkte omgevingen (bijv. mobiele apparaten, embedded systemen) kan het annuleren van onnodige bewerkingen waardevolle resources vrijmaken en de prestaties verbeteren. Bijvoorbeeld, het annuleren van een grote afbeelding download als de gebruiker voorbij dat gedeelte van de pagina scrolt.
Introductie van AbortController en AbortSignal
De AbortController
interface is ontworpen om het probleem van het annuleren van asynchrone bewerkingen op te lossen. Het bestaat uit twee belangrijke componenten:
- AbortController: Dit object beheert het annuleringssignaal. Het heeft een enkele methode,
abort()
, die wordt gebruikt om een annuleringsverzoek te signaleren. - AbortSignal: Dit object vertegenwoordigt het signaal dat een bewerking moet worden afgebroken. Het is gekoppeld aan een
AbortController
en wordt doorgegeven aan de asynchrone bewerking die annuleerbaar moet zijn.
Basisgebruik: Fetch-verzoeken Annuleren
Laten we beginnen met een eenvoudig voorbeeld van het annuleren van een fetch
verzoek:
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);
}
});
// Om het fetch-verzoek te annuleren:
controller.abort();
Uitleg:
- We creëren een
AbortController
instantie. - We verkrijgen het bijbehorende
AbortSignal
van decontroller
. - We geven het
signal
door aan defetch
opties. - Als we het verzoek moeten annuleren, roepen we
controller.abort()
aan. - In het
.catch()
blok controleren we of de fout eenAbortError
is. Zo ja, dan weten we dat het verzoek is geannuleerd.
AbortError Afhandelen
Wanneer controller.abort()
wordt aangeroepen, wordt het fetch
verzoek afgewezen met een AbortError
. Het is cruciaal om deze fout op de juiste manier in uw code af te handelen. Als u dit niet doet, kan dit leiden tot onafgehandelde promise-afwijzingen en onverwacht gedrag.
Hier is een robuuster voorbeeld met foutafhandeling:
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; // Of gooi de fout omhoog om verder afgehandeld te worden
} else {
console.error('Fetch error:', error);
throw error; // Gooi de fout opnieuw om verder afgehandeld te worden
}
}
}
fetchData();
// Om het fetch-verzoek te annuleren:
controller.abort();
Best Practices voor het Afhandelen van AbortError:
- Controleer de foutnaam: Controleer altijd of
error.name === 'AbortError'
om er zeker van te zijn dat u het juiste fouttype afhandelt. - Retourneer een standaardwaarde of gooi opnieuw: Afhankelijk van de logica van uw applicatie, wilt u mogelijk een standaardwaarde retourneren (bijv.
null
) of de fout opnieuw gooien om verderop in de call stack te worden afgehandeld. - Ruim resources op: Als de asynchrone bewerking resources heeft toegewezen (bijv. timers, event listeners), ruim ze dan op in de
AbortError
handler.
Timers Annuleren met AbortSignal
De AbortSignal
kan ook worden gebruikt om timers te annuleren die zijn gemaakt met setTimeout
of setInterval
. Dit vereist iets meer handmatig werk, omdat de ingebouwde timerfuncties AbortSignal
niet direct ondersteunen. U moet een aangepaste functie maken die luistert naar het abort-signaal en de timer wist wanneer dit wordt geactiveerd.
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));
// Om de timeout te annuleren:
controller.abort();
Uitleg:
- De
cancellableTimeout
functie accepteert een callback, een vertraging en eenAbortSignal
als argumenten. - Het stelt een
setTimeout
in en slaat de timeout ID op. - Het voegt een event listener toe aan de
AbortSignal
die luistert naar deabort
event. - Wanneer de
abort
event wordt geactiveerd, wist de event listener de timeout en wijst de promise af.
Event Listeners Annuleren
Net als bij timers, kunt u AbortSignal
gebruiken om event listeners te annuleren. Dit is vooral handig wanneer u event listeners wilt verwijderen die zijn gekoppeld aan een component dat wordt ontkoppeld.
const controller = new AbortController();
const signal = controller.signal;
const button = document.getElementById('myButton');
button.addEventListener('click', () => {
console.log('Button clicked!');
}, { signal });
// Om de event listener te annuleren:
controller.abort();
Uitleg:
- We geven het
signal
door als een optie aan deaddEventListener
methode. - Wanneer
controller.abort()
wordt aangeroepen, wordt de event listener automatisch verwijderd.
AbortController in React Components
In React kunt u AbortController
gebruiken om asynchrone bewerkingen te annuleren wanneer een component ontkoppelt. Dit is essentieel om geheugenlekken en fouten te voorkomen die worden veroorzaakt door het bijwerken van ontkoppelde componenten. Hier is een voorbeeld met behulp van de useEffect
hook:
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(); // Annuleer het fetch-verzoek wanneer de component ontkoppelt
};
}, []); // Lege dependency array zorgt ervoor dat dit effect slechts één keer wordt uitgevoerd bij het monteren
return (
{data ? (
Data: {JSON.stringify(data)}
) : (
Loading...
)}
);
}
export default MyComponent;
Uitleg:
- We creëren een
AbortController
binnen deuseEffect
hook. - We geven het
signal
door aan hetfetch
verzoek. - We retourneren een cleanup functie van de
useEffect
hook. Deze functie wordt aangeroepen wanneer de component ontkoppelt. - Binnen de cleanup functie roepen we
controller.abort()
aan om het fetch-verzoek te annuleren.
Geavanceerde Gebruiksscenario's
AbortSignals Chaining
Soms wilt u mogelijk meerdere AbortSignal
s aan elkaar koppelen. U hebt bijvoorbeeld een bovenliggende component die bewerkingen in de onderliggende componenten moet annuleren. U kunt dit bereiken door een nieuwe AbortController
te maken en het signaal ervan door te geven aan zowel de bovenliggende als de onderliggende component.
AbortController Gebruiken met Third-Party Libraries
Als u een third-party library gebruikt die AbortSignal
niet direct ondersteunt, moet u mogelijk uw code aanpassen om met het annuleringsmechanisme van de library te werken. Dit kan inhouden dat u de asynchrone functies van de library verpakt in uw eigen functies die de AbortSignal
afhandelen.
Voordelen van het Gebruiken van AbortController
- Verbeterde Prestaties: Het annuleren van onnodige bewerkingen kan het netwerkverkeer, het CPU-gebruik en het geheugengebruik verminderen, wat leidt tot verbeterde prestaties, vooral op apparaten met beperkte resources.
- Schonere Code:
AbortController
biedt een gestandaardiseerde en elegante manier om annulering te beheren, waardoor uw code leesbaarder en onderhoudbaarder wordt. - Voorkomen van Geheugenlekken: Het annuleren van asynchrone bewerkingen die zijn gekoppeld aan ontkoppelde componenten voorkomt geheugenlekken en fouten die worden veroorzaakt door het bijwerken van ontkoppelde componenten.
- Betere Gebruikerservaring: Het annuleren van irrelevante verzoeken kan de gebruikerservaring verbeteren door te voorkomen dat verouderde informatie wordt weergegeven en de waargenomen latency te verminderen.
Browsercompatibiliteit
AbortController
wordt breed ondersteund in moderne browsers, waaronder Chrome, Firefox, Safari en Edge. U kunt de compatibiliteitstabel op de MDN Web Docs raadplegen voor de meest recente informatie.
Polyfills
Voor oudere browsers die AbortController
niet native ondersteunen, kunt u een polyfill gebruiken. Een polyfill is een stuk code dat de functionaliteit van een nieuwere functie in oudere browsers biedt. Er zijn verschillende AbortController
polyfills online beschikbaar.
Conclusie
De AbortController
interface is een krachtig hulpmiddel voor het beheren van asynchrone bewerkingen in JavaScript. Door AbortController
te gebruiken, kunt u schonere, beter presterende en robuustere code schrijven die annulering elegant afhandelt. Of u nu gegevens ophaalt van API's, timers instelt of event listeners beheert, AbortController
kan u helpen de algehele kwaliteit van uw webapplicaties te verbeteren.