Svenska

Lär dig använda JavaScripts AbortController för att effektivt avbryta asynkrona operationer som fetch-anrop, timers och mer.

JavaScript AbortController: Bemästra avbrytande av asynkrona operationer

Inom modern webbutveckling är asynkrona operationer allestädes närvarande. Att hämta data från API:er, ställa in timers och hantera användarinteraktioner involverar ofta kod som körs oberoende och potentiellt under en längre tid. Det finns dock scenarier där du behöver avbryta dessa operationer innan de slutförs. Det är här AbortController-gränssnittet i JavaScript kommer till undsättning. Det ger ett rent och effektivt sätt att signalera avbrytningsförfrågningar till DOM-operationer och andra asynkrona uppgifter.

Förstå behovet av avbrytande

Innan vi dyker ner i de tekniska detaljerna, låt oss förstå varför det är viktigt att avbryta asynkrona operationer. Tänk på dessa vanliga scenarier:

Introduktion till AbortController och AbortSignal

AbortController-gränssnittet är utformat för att lösa problemet med att avbryta asynkrona operationer. Det består av två nyckelkomponenter:

Grundläggande användning: Avbryta Fetch-anrop

Låt oss börja med ett enkelt exempel på att avbryta ett fetch-anrop:


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 avbrutet');
    } else {
      console.error('Fetch-fel:', error);
    }
  });

// För att avbryta fetch-anropet:
controller.abort();

Förklaring:

  1. Vi skapar en AbortController-instans.
  2. Vi hämtar den associerade AbortSignal från controller.
  3. Vi skickar signal till fetch-alternativen.
  4. Om vi behöver avbryta anropet, anropar vi controller.abort().
  5. I .catch()-blocket kontrollerar vi om felet är en AbortError. Om det är det, vet vi att anropet avbröts.

Hantera AbortError

När controller.abort() anropas, kommer fetch-anropet att avvisas med en AbortError. Det är avgörande att hantera detta fel på ett lämpligt sätt i din kod. Att underlåta att göra det kan leda till ohanterade löftesavvisningar och oväntat beteende.

Här är ett mer robust exempel med felhantering:


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 avbrutet');
      return null; // Eller kasta felet för att hanteras högre upp
    } else {
      console.error('Fetch-fel:', error);
      throw error; // Kasta om felet för att hanteras högre upp
    }
  }
}

fetchData();

// För att avbryta fetch-anropet:
controller.abort();

Bästa praxis för hantering av AbortError:

Avbryta timers med AbortSignal

AbortSignal kan också användas för att avbryta timers skapade med setTimeout eller setInterval. Detta kräver lite mer manuellt arbete, eftersom de inbyggda timerfunktionerna inte direkt stöder AbortSignal. Du behöver skapa en anpassad funktion som lyssnar på avbrytningssignalen och rensar timern när den utlö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 avbruten'));
    });
  });

  return timeoutPromise;
}

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


cancellableTimeout(() => {
  console.log('Timeout exekverad');
}, 2000, signal)
.then(() => console.log("Timeout slutförd framgångsrikt"))
.catch(err => console.log(err));

// För att avbryta timeouten:
controller.abort();

Förklaring:

  1. cancellableTimeout-funktionen tar en callback, en fördröjning och en AbortSignal som argument.
  2. Den sätter upp en setTimeout och lagrar timeout-ID:t.
  3. Den lägger till en händelselyssnare till AbortSignal som lyssnar efter abort-händelsen.
  4. När abort-händelsen utlöses, rensar händelselyssnaren timeouten och avvisar löftet.

Avbryta händelselyssnare

Liknande timers kan du använda AbortSignal för att avbryta händelselyssnare. Detta är särskilt användbart när du vill ta bort händelselyssnare associerade med en komponent som monteras av.


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

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

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

// För att avbryta händelselyssnaren:
controller.abort();

Förklaring:

  1. Vi skickar signal som ett alternativ till addEventListener-metoden.
  2. När controller.abort() anropas kommer händelselyssnaren automatiskt att tas bort.

AbortController i React-komponenter

I React kan du använda AbortController för att avbryta asynkrona operationer när en komponent monteras av. Detta är viktigt för att förhindra minnesläckor och fel som orsakas av att uppdatera avmonterade komponenter. Här är ett exempel som använder useEffect-hooken:


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 avbrutet');
        } else {
          console.error('Fetch-fel:', error);
        }
      }
    }

    fetchData();

    return () => {
      controller.abort(); // Avbryt fetch-anropet när komponenten monteras av
    };
  }, []); // Tom beroendearray säkerställer att denna effekt körs endast en gång vid montering

  return (
    
{data ? (

Data: {JSON.stringify(data)}

) : (

Laddar...

)}
); } export default MyComponent;

Förklaring:

  1. Vi skapar en AbortController inom useEffect-hooken.
  2. Vi skickar signal till fetch-anropet.
  3. Vi returnerar en städfunktion från useEffect-hooken. Denna funktion kommer att anropas när komponenten monteras av.
  4. Inuti städfunktionen anropar vi controller.abort() för att avbryta fetch-anropet.

Avancerade användningsfall

Kedja AbortSignals

Ibland kanske du vill kedja flera AbortSignals tillsammans. Du kanske till exempel har en föräldrakomponent som behöver avbryta operationer i sina barnkomponenter. Du kan uppnå detta genom att skapa en ny AbortController och skicka dess signal till både föräldra- och barnkomponenterna.

Använda AbortController med tredjepartsbibliotek

Om du använder ett tredjepartsbibliotek som inte direkt stöder AbortSignal, kan du behöva anpassa din kod för att fungera med bibliotekets avbrytningsmekanism. Detta kan innebära att du slår in bibliotekets asynkrona funktioner i dina egna funktioner som hanterar AbortSignal.

Fördelar med att använda AbortController

Webbläsarstöd

AbortController stöds brett i moderna webbläsare, inklusive Chrome, Firefox, Safari och Edge. Du kan kontrollera kompatibilitetstabellen på MDN Web Docs för den senaste informationen.

Polyfills

För äldre webbläsare som inte har inbyggt stöd för AbortController kan du använda en polyfill. En polyfill är en kodbit som tillhandahåller funktionaliteten hos en nyare funktion i äldre webbläsare. Det finns flera AbortController-polyfills tillgängliga online.

Slutsats

AbortController-gränssnittet är ett kraftfullt verktyg för att hantera asynkrona operationer i JavaScript. Genom att använda AbortController kan du skriva renare, mer högpresterande och mer robust kod som hanterar avbrytande på ett elegant sätt. Oavsett om du hämtar data från API:er, ställer in timers eller hanterar händelselyssnare, kan AbortController hjälpa dig att förbättra den övergripande kvaliteten på dina webbapplikationer.

Vidare läsning