Sužinokite, kaip naudoti JavaScript AbortController norint efektyviai atšaukti asinchronines operacijas, tokias kaip fetch užklausos, laikmačiai ir kt., užtikrinant švaresnį ir našesnį kodą.
JavaScript AbortController: asinchroninių operacijų atšaukimo įvaldymas
Šiuolaikiniame web kūrime asinchroninės operacijos yra visur. Duomenų gavimas iš API, laikmačių nustatymas ir vartotojo sąveikų valdymas dažnai apima kodą, kuris veikia nepriklausomai ir potencialiai ilgą laiką. Tačiau yra scenarijų, kai reikia atšaukti šias operacijas, kol jos nebaigtos. Čia į pagalbą ateina AbortController
sąsaja JavaScript'e. Ji suteikia švarų ir efektyvų būdą siųsti atšaukimo signalus DOM operacijoms ir kitoms asinchroninėms užduotims.
Atšaukimo poreikio supratimas
Prieš gilinantis į technines detales, supraskime, kodėl svarbu atšaukti asinchronines operacijas. Apsvarstykite šiuos dažnus scenarijus:
- Vartotojo navigacija: Vartotojas inicijuoja paieškos užklausą, kuri sukelia API užklausą. Jei jis greitai pereina į kitą puslapį, kol užklausa nebaigta, pradinė užklausa tampa nebeaktuali ir turėtų būti atšaukta, kad būtų išvengta nereikalingo tinklo srauto ir galimų šalutinių poveikių.
- Laikmačio valdymas: Nustatote asinchroninės operacijos laiko limitą. Jei operacija baigiama anksčiau nei sueina laikas, turėtumėte atšaukti laikmatį, kad išvengtumėte nereikalingo kodo vykdymo.
- Komponento atjungimas (Unmounting): Front-end sistemose, tokiose kaip React ar Vue.js, komponentai dažnai vykdo asinchronines užklausas. Kai komponentas yra atjungiamas, visos su juo susijusios vykdomos užklausos turėtų būti atšauktos, kad būtų išvengta atminties nutekėjimo ir klaidų, kylančių dėl bandymo atnaujinti atjungtus komponentus.
- Išteklių apribojimai: Aplinkose su ribotais ištekliais (pvz., mobiliuosiuose įrenginiuose, įterptinėse sistemose), nereikalingų operacijų atšaukimas gali atlaisvinti vertingus išteklius ir pagerinti našumą. Pavyzdžiui, didelio paveikslėlio atsisiuntimo atšaukimas, jei vartotojas prascrollina pro tą puslapio dalį.
Pristatome AbortController ir AbortSignal
AbortController
sąsaja yra skirta spręsti asinchroninių operacijų atšaukimo problemą. Ją sudaro du pagrindiniai komponentai:
- AbortController: Šis objektas valdo atšaukimo signalą. Jis turi vieną metodą,
abort()
, kuris naudojamas atšaukimo užklausai signalizuoti. - AbortSignal: Šis objektas atspindi signalą, kad operacija turėtų būti nutraukta. Jis yra susietas su
AbortController
ir perduodamas asinchroninei operacijai, kurią reikia padaryti atšaukiamą.
Pagrindinis naudojimas: Fetch užklausų atšaukimas
Pradėkime nuo paprasto fetch
užklausos atšaukimo pavyzdžio:
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();
Paaiškinimas:
- Suriame
AbortController
egzempliorių. - Iš
controller
gauname susietąAbortSignal
. - Perduodame
signal
įfetch
parinktis. - Jei reikia atšaukti užklausą, iškviečiame
controller.abort()
. .catch()
bloke tikriname, ar klaida yraAbortError
. Jei taip, žinome, kad užklausa buvo atšaukta.
AbortError apdorojimas
Kai iškviečiamas controller.abort()
, fetch
užklausa bus atmesta su AbortError
klaida. Labai svarbu tinkamai apdoroti šią klaidą savo kode. To nepadarius, gali kilti neapdorotų pažadų (promise) atmetimų ir netikėto elgesio.
Štai patikimesnis pavyzdys su klaidų apdorojimu:
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();
Gerosios AbortError apdorojimo praktikos:
- Tikrinkite klaidos pavadinimą: Visada tikrinkite, ar
error.name === 'AbortError'
, kad įsitikintumėte, jog apdorojate teisingą klaidos tipą. - Grąžinkite numatytąją reikšmę arba permeskite klaidą: Priklausomai nuo jūsų programos logikos, galbūt norėsite grąžinti numatytąją reikšmę (pvz.,
null
) arba permesti klaidą, kad ji būtų apdorota aukštesniame iškvietimų dėklo (call stack) lygmenyje. - Išvalykite išteklius: Jei asinchroninė operacija priskyrė kokių nors išteklių (pvz., laikmačių, įvykių klausytojų), išvalykite juos
AbortError
apdorojimo bloke.
Laikmačių atšaukimas su AbortSignal
AbortSignal
taip pat galima naudoti atšaukti laikmačius, sukurtus su setTimeout
ar setInterval
. Tam reikia šiek tiek daugiau rankinio darbo, nes integruotos laikmačių funkcijos tiesiogiai nepalaiko AbortSignal
. Reikia sukurti pasirinktinę funkciją, kuri klausytųsi atšaukimo signalo ir išvalytų laikmatį, kai jis suveikia.
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();
Paaiškinimas:
- Funkcija
cancellableTimeout
priima atgalinio iškvietimo funkciją (callback), delsą irAbortSignal
kaip argumentus. - Ji nustato
setTimeout
ir išsaugo laikmačio ID. - Ji prideda įvykių klausytoją prie
AbortSignal
, kuris klausoabort
įvykio. - Kai suveikia
abort
įvykis, įvykių klausytojas išvalo laikmatį ir atmeta pažadą (promise).
Įvykių klausytojų (Event Listeners) atšaukimas
Panašiai kaip su laikmačiais, galite naudoti AbortSignal
norėdami atšaukti įvykių klausytojus. Tai ypač naudinga, kai norite pašalinti įvykių klausytojus, susijusius su komponentu, kuris yra atjungiamas.
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();
Paaiškinimas:
- Perduodame
signal
kaip parinktį įaddEventListener
metodą. - Kai iškviečiamas
controller.abort()
, įvykių klausytojas bus automatiškai pašalintas.
AbortController React komponentuose
React aplinkoje galite naudoti AbortController
norėdami atšaukti asinchronines operacijas, kai komponentas yra atjungiamas. Tai būtina norint išvengti atminties nutekėjimo ir klaidų, kylančių dėl bandymo atnaujinti atjungtus komponentus. Štai pavyzdys naudojant useEffect
kablį (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(); // 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;
Paaiškinimas:
- Sukuriame
AbortController
useEffect
kablio viduje. - Perduodame
signal
įfetch
užklausą. - Grąžiname išvalymo funkciją iš
useEffect
kablio. Ši funkcija bus iškviesta, kai komponentas bus atjungtas. - Išvalymo funkcijos viduje iškviečiame
controller.abort()
, kad atšauktume fetch užklausą.
Pažangesni naudojimo atvejai
AbortSignal grandinimas
Kartais gali prireikti sujungti kelis AbortSignal
į grandinę. Pavyzdžiui, galite turėti pagrindinį komponentą, kuris turi atšaukti operacijas savo antriniuose komponentuose. Tai galite pasiekti sukurdami naują AbortController
ir perduodami jo signalą tiek pagrindiniam, tiek antriniams komponentams.
AbortController naudojimas su trečiųjų šalių bibliotekomis
Jei naudojate trečiosios šalies biblioteką, kuri tiesiogiai nepalaiko AbortSignal
, gali tekti pritaikyti savo kodą, kad jis veiktų su tos bibliotekos atšaukimo mechanizmu. Tai gali apimti bibliotekos asinchroninių funkcijų apgaubimą savo funkcijomis, kurios apdoroja AbortSignal
.
AbortController naudojimo privalumai
- Geresnis našumas: Nereikalingų operacijų atšaukimas gali sumažinti tinklo srautą, procesoriaus naudojimą ir atminties suvartojimą, o tai lemia geresnį našumą, ypač įrenginiuose su ribotais ištekliais.
- Švaresnis kodas:
AbortController
suteikia standartizuotą ir elegantišką būdą valdyti atšaukimą, todėl jūsų kodas tampa lengviau skaitomas ir prižiūrimas. - Atminties nutekėjimo prevencija: Asinchroninių operacijų, susijusių su atjungtais komponentais, atšaukimas apsaugo nuo atminties nutekėjimo ir klaidų, kylančių dėl bandymo atnaujinti atjungtus komponentus.
- Geresnė vartotojo patirtis: Nebeaktualų užklausų atšaukimas gali pagerinti vartotojo patirtį, užkertant kelią pasenusios informacijos rodymui ir sumažinant juntamą delsą.
Naršyklių suderinamumas
AbortController
yra plačiai palaikomas šiuolaikinėse naršyklėse, įskaitant Chrome, Firefox, Safari ir Edge. Naujausią informaciją galite patikrinti suderinamumo lentelėje MDN Web Docs svetainėje.
Polyfill'ai
Senesnėms naršyklėms, kurios natūraliai nepalaiko AbortController
, galite naudoti „polyfill“. „Polyfill“ yra kodo dalis, kuri suteikia naujesnės funkcijos funkcionalumą senesnėse naršyklėse. Internete yra prieinami keli AbortController
„polyfill'ai“.
Išvada
AbortController
sąsaja yra galingas įrankis asinchroninėms operacijoms valdyti JavaScript'e. Naudodami AbortController
, galite rašyti švaresnį, našesnį ir patikimesnį kodą, kuris sklandžiai tvarkosi su atšaukimu. Nesvarbu, ar gaunate duomenis iš API, nustatote laikmačius, ar valdote įvykių klausytojus, AbortController
gali padėti pagerinti bendrą jūsų web programų kokybę.