Hrvatski

Naučite kako koristiti JavaScript AbortController za učinkovito prekidanje asinkronih operacija poput fetch zahtjeva, tajmera i više, osiguravajući čišći i brži kod.

JavaScript AbortController: Ovladavanje prekidom asinkronih operacija

U modernom web razvoju, asinkrone operacije su sveprisutne. Dohvaćanje podataka s API-ja, postavljanje tajmera i rukovanje korisničkim interakcijama često uključuju kod koji se izvršava neovisno i potencijalno dulje vrijeme. Međutim, postoje scenariji u kojima trebate prekinuti te operacije prije nego što se završe. Tu u pomoć priskače AbortController sučelje u JavaScriptu. Ono pruža čist i učinkovit način za slanje signala o prekidu DOM operacijama i drugim asinkronim zadacima.

Razumijevanje potrebe za prekidom

Prije nego što se upustimo u tehničke detalje, razjasnimo zašto je prekidanje asinkronih operacija važno. Razmotrite ove uobičajene scenarije:

Uvod u AbortController i AbortSignal

Sučelje AbortController dizajnirano je za rješavanje problema prekidanja asinkronih operacija. Sastoji se od dvije ključne komponente:

Osnovna upotreba: Prekidanje Fetch zahtjeva

Počnimo s jednostavnim primjerom prekidanja fetch zahtjeva:


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);
    }
  });

// Za prekid fetch zahtjeva:
controller.abort();

Objašnjenje:

  1. Stvaramo instancu AbortController.
  2. Dobivamo pripadajući AbortSignal iz controllera.
  3. Prosljeđujemo signal u opcije fetch zahtjeva.
  4. Ako trebamo prekinuti zahtjev, pozivamo controller.abort().
  5. U .catch() bloku provjeravamo je li pogreška AbortError. Ako jest, znamo da je zahtjev prekinut.

Rukovanje AbortErrorom

Kada se pozove controller.abort(), fetch zahtjev će biti odbačen s AbortErrorom. Ključno je pravilno obraditi ovu pogrešku u vašem kodu. Ako to ne učinite, može doći do neobrađenih odbacivanja promisea i neočekivanog ponašanja.

Evo robusnijeg primjera s rukovanjem pogreškama:


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; // Ili bacite pogrešku da se obradi na višoj razini
    } else {
      console.error('Fetch error:', error);
      throw error; // Ponovno bacite pogrešku da se obradi na višoj razini
    }
  }
}

fetchData();

// Za prekid fetch zahtjeva:
controller.abort();

Najbolje prakse za rukovanje AbortErrorom:

Prekidanje tajmera pomoću AbortSignala

AbortSignal se također može koristiti za prekidanje tajmera stvorenih pomoću setTimeout ili setInterval. To zahtijeva malo više ručnog rada, jer ugrađene funkcije za tajmere ne podržavaju izravno AbortSignal. Morate stvoriti prilagođenu funkciju koja osluškuje signal za prekid i čisti tajmer kada se aktivira.


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));

// Za prekid tajmera:
controller.abort();

Objašnjenje:

  1. Funkcija cancellableTimeout prima povratnu funkciju (callback), odgodu (delay) i AbortSignal kao argumente.
  2. Postavlja setTimeout i pohranjuje ID tajmera.
  3. Dodaje osluškivač događaja na AbortSignal koji osluškuje abort događaj.
  4. Kada se abort događaj aktivira, osluškivač događaja čisti tajmer i odbacuje promise.

Prekidanje osluškivača događaja (Event Listeners)

Slično tajmerima, možete koristiti AbortSignal za prekidanje osluškivača događaja. To je posebno korisno kada želite ukloniti osluškivače događaja povezane s komponentom koja se demontira.


const controller = new AbortController();
const signal = controller.signal;

const button = document.getElementById('myButton');

button.addEventListener('click', () => {
  console.log('Button clicked!');
}, { signal });

// Za prekid osluškivača događaja:
controller.abort();

Objašnjenje:

  1. Prosljeđujemo signal kao opciju u metodu addEventListener.
  2. Kada se pozove controller.abort(), osluškivač događaja će biti automatski uklonjen.

AbortController u React komponentama

U Reactu možete koristiti AbortController za prekidanje asinkronih operacija kada se komponenta demontira. To je ključno za sprječavanje curenja memorije i pogrešaka uzrokovanih ažuriranjem demontiranih komponenti. Evo primjera korištenja useEffect hooka:


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(); // Prekini fetch zahtjev kada se komponenta demontira
    };
  }, []); // Prazno polje ovisnosti osigurava da se ovaj efekt izvrši samo jednom prilikom montiranja

  return (
    
{data ? (

Data: {JSON.stringify(data)}

) : (

Loading...

)}
); } export default MyComponent;

Objašnjenje:

  1. Stvaramo AbortController unutar useEffect hooka.
  2. Prosljeđujemo signal u fetch zahtjev.
  3. Vraćamo funkciju za čišćenje iz useEffect hooka. Ova funkcija će se pozvati kada se komponenta demontira.
  4. Unutar funkcije za čišćenje, pozivamo controller.abort() kako bismo prekinuli fetch zahtjev.

Napredni slučajevi upotrebe

Ulančavanje AbortSignala

Ponekad ćete možda htjeti ulančati više AbortSignala. Na primjer, možda imate roditeljsku komponentu koja treba prekinuti operacije u svojim dječjim komponentama. To možete postići stvaranjem novog AbortControllera i prosljeđivanjem njegovog signala i roditeljskoj i dječjim komponentama.

Korištenje AbortControllera s bibliotekama trećih strana

Ako koristite biblioteku treće strane koja izravno ne podržava AbortSignal, možda ćete morati prilagoditi svoj kod kako bi radio s mehanizmom za prekid te biblioteke. To može uključivati omatanje asinkronih funkcija biblioteke u vlastite funkcije koje obrađuju AbortSignal.

Prednosti korištenja AbortControllera

Kompatibilnost s preglednicima

AbortController je široko podržan u modernim preglednicima, uključujući Chrome, Firefox, Safari i Edge. Možete provjeriti tablicu kompatibilnosti na MDN Web Docs za najnovije informacije.

Polyfillovi

Za starije preglednike koji izvorno ne podržavaju AbortController, možete koristiti polyfill. Polyfill je dio koda koji pruža funkcionalnost novije značajke u starijim preglednicima. Na internetu je dostupno nekoliko polyfillova za AbortController.

Zaključak

Sučelje AbortController moćan je alat za upravljanje asinkronim operacijama u JavaScriptu. Korištenjem AbortControllera možete pisati čišći, brži i robusniji kod koji elegantno obrađuje prekide. Bilo da dohvaćate podatke s API-ja, postavljate tajmere ili upravljate osluškivačima događaja, AbortController vam može pomoći poboljšati ukupnu kvalitetu vaših web aplikacija.

Dodatna literatura