Dansk

Lær hvordan du bruger JavaScripts AbortController til effektivt at annullere asynkrone operationer som fetch-forespørgsler, timere og mere, hvilket sikrer renere og mere performant kode.

JavaScript AbortController: Mastering annullering af asynkrone operationer

I moderne webudvikling er asynkrone operationer allestedsnærværende. Hentning af data fra API'er, indstilling af timere og håndtering af brugerinteraktioner involverer ofte kode, der kører uafhængigt og potentielt i en længere periode. Der er dog scenarier, hvor du skal annullere disse operationer, før de er færdige. Det er her, AbortController-interfacet i JavaScript kommer til undsætning. Det giver en ren og effektiv måde at signalere annulleringsanmodninger til DOM-operationer og andre asynkrone opgaver.

Forståelse af behovet for annullering

Før vi dykker ned i de tekniske detaljer, skal vi forstå, hvorfor annullering af asynkrone operationer er vigtigt. Overvej disse almindelige scenarier:

Introduktion til AbortController og AbortSignal

AbortController-interfacet er designet til at løse problemet med annullering af asynkrone operationer. Det består af to nøglekomponenter:

Grundlæggende brug: Annullering af Fetch-forespørgsler

Lad os starte med et simpelt eksempel på at annullere en fetch-forespørgsel:


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

Forklaring:

  1. Vi opretter en AbortController-instans.
  2. Vi henter det tilknyttede AbortSignal fra controller.
  3. Vi sender signal til fetch-valgmulighederne.
  4. Hvis vi skal annullere anmodningen, kalder vi controller.abort().
  5. I .catch()-blokken kontrollerer vi, om fejlen er en AbortError. Hvis det er tilfældet, ved vi, at anmodningen blev annulleret.

Håndtering af AbortError

Når controller.abort() kaldes, afvises fetch-anmodningen med en AbortError. Det er afgørende at håndtere denne fejl korrekt i din kode. Hvis du undlader at gøre det, kan det føre til uhåndterede løftede afvisninger og uventet adfærd.

Her er et mere robust eksempel med fejlhåndtering:


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

Bedste praksis for håndtering af AbortError:

Annullering af timere med AbortSignal

AbortSignal kan også bruges til at annullere timere, der er oprettet med setTimeout eller setInterval. Dette kræver lidt mere manuelt arbejde, da de indbyggede timerfunktioner ikke direkte understøtter AbortSignal. Du skal oprette en brugerdefineret funktion, der lytter efter abortsignalet og rydder timeren, når den udløses.


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

Forklaring:

  1. cancellableTimeout-funktionen tager en callback, en forsinkelse og et AbortSignal som argumenter.
  2. Den opsætter en setTimeout og gemmer timeout-id'et.
  3. Den tilføjer en event listener til AbortSignal, der lytter efter abort-eventen.
  4. Når abort-eventen udløses, rydder event listeneren timeouten og afviser løftet.

Annullering af Event Listeners

På samme måde som med timere kan du bruge AbortSignal til at annullere event listeners. Dette er især nyttigt, når du vil fjerne event listeners, der er knyttet til en komponent, der er ved at blive umonteret.


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

Forklaring:

  1. Vi sender signal som en indstilling til addEventListener-metoden.
  2. Når controller.abort() kaldes, fjernes event listeneren automatisk.

AbortController i React-komponenter

I React kan du bruge AbortController til at annullere asynkrone operationer, når en komponent unmountes. Dette er afgørende for at forhindre hukommelseslækager og fejl forårsaget af opdatering af umonterede komponenter. Her er et eksempel ved hjælp af useEffect-hooket:


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(); // Annuller fetch-anmodningen, når komponenten unmountes
    };
  }, []); // Empty dependency array ensures this effect runs only once on mount

  return (
    
{data ? (

Data: {JSON.stringify(data)}

) : (

Loading...

)}
); } export default MyComponent;

Forklaring:

  1. Vi opretter en AbortController i useEffect-hooket.
  2. Vi sender signal til fetch-anmodningen.
  3. Vi returnerer en oprydningsfunktion fra useEffect-hooket. Denne funktion kaldes, når komponenten unmountes.
  4. Inde i oprydningsfunktionen kalder vi controller.abort() for at annullere fetch-anmodningen.

Avancerede brugsscenarier

Kædning af AbortSignals

Nogle gange vil du muligvis kæde flere AbortSignal sammen. Du kan f.eks. have en overordnet komponent, der skal annullere operationer i sine underordnede komponenter. Du kan opnå dette ved at oprette en ny AbortController og sende dets signal til både de overordnede og underordnede komponenter.

Brug af AbortController med tredjepartsbiblioteker

Hvis du bruger et tredjepartsbibliotek, der ikke direkte understøtter AbortSignal, skal du muligvis tilpasse din kode, så den fungerer med bibliotekets annulleringsmekanisme. Dette kan involvere at indpakke bibliotekets asynkrone funktioner i dine egne funktioner, der håndterer AbortSignal.

Fordele ved at bruge AbortController

Browserkompatibilitet

AbortController understøttes bredt i moderne browsere, herunder Chrome, Firefox, Safari og Edge. Du kan tjekke kompatibilitetstabellen på MDN Web Docs for de seneste oplysninger.

Polyfills

For ældre browsere, der ikke oprindeligt understøtter AbortController, kan du bruge en polyfill. En polyfill er et stykke kode, der giver funktionaliteten af en nyere funktion i ældre browsere. Der er flere AbortController polyfills tilgængelige online.

Konklusion

AbortController-interfacet er et kraftfuldt værktøj til at administrere asynkrone operationer i JavaScript. Ved at bruge AbortController kan du skrive renere, mere performant og mere robust kode, der håndterer annullering på en elegant måde. Uanset om du henter data fra API'er, indstiller timere eller administrerer event listeners, kan AbortController hjælpe dig med at forbedre den overordnede kvalitet af dine webapplikationer.

Yderligere læsning