Deutsch

Lernen Sie, wie Sie mit dem JavaScript AbortController asynchrone Operationen wie Fetch-Anfragen und Timer effektiv abbrechen, um sauberen und performanteren Code zu schreiben.

JavaScript AbortController: Meisterung der Abbrechung asynchroner Operationen

In der modernen Webentwicklung sind asynchrone Operationen allgegenwärtig. Das Abrufen von Daten von APIs, das Setzen von Timern und die Verarbeitung von Benutzerinteraktionen beinhalten oft Code, der unabhängig und potenziell über einen längeren Zeitraum läuft. Es gibt jedoch Szenarien, in denen Sie diese Operationen abbrechen müssen, bevor sie abgeschlossen sind. Hier kommt die AbortController-Schnittstelle in JavaScript zur Rettung. Sie bietet eine saubere und effiziente Möglichkeit, Abbruchanfragen an DOM-Operationen und andere asynchrone Aufgaben zu signalisieren.

Die Notwendigkeit des Abbruchs verstehen

Bevor wir uns mit den technischen Details befassen, wollen wir verstehen, warum das Abbrechen asynchroner Operationen wichtig ist. Betrachten Sie diese gängigen Szenarien:

Einführung in AbortController und AbortSignal

Die AbortController-Schnittstelle wurde entwickelt, um das Problem des Abbrechens asynchroner Operationen zu lösen. Sie besteht aus zwei Schlüsselkomponenten:

Grundlegende Verwendung: Abbrechen von Fetch-Anfragen

Beginnen wir mit einem einfachen Beispiel für das Abbrechen einer fetch-Anfrage:


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('Daten:', data);
  })
  .catch(error => {
    if (error.name === 'AbortError') {
      console.log('Fetch abgebrochen');
    } else {
      console.error('Fetch-Fehler:', error);
    }
  });

// Um die Fetch-Anfrage abzubrechen:
controller.abort();

Erklärung:

  1. Wir erstellen eine AbortController-Instanz.
  2. Wir erhalten das zugehörige AbortSignal vom controller.
  3. Wir übergeben das signal an die fetch-Optionen.
  4. Wenn wir die Anfrage abbrechen müssen, rufen wir controller.abort() auf.
  5. Im .catch()-Block prüfen wir, ob der Fehler ein AbortError ist. Wenn ja, wissen wir, dass die Anfrage abgebrochen wurde.

Umgang mit AbortError

Wenn controller.abort() aufgerufen wird, wird die fetch-Anfrage mit einem AbortError zurückgewiesen. Es ist entscheidend, diesen Fehler in Ihrem Code angemessen zu behandeln. Andernfalls kann dies zu unbehandelten Promise-Rejections und unerwartetem Verhalten führen.

Hier ist ein robusteres Beispiel mit Fehlerbehandlung:


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('Daten:', data);
    return data;
  } catch (error) {
    if (error.name === 'AbortError') {
      console.log('Fetch abgebrochen');
      return null; // Oder den Fehler weiter nach oben werfen, um ihn dort zu behandeln
    } else {
      console.error('Fetch-Fehler:', error);
      throw error; // Den Fehler weiter nach oben werfen, um ihn dort zu behandeln
    }
  }
}

fetchData();

// Um die Fetch-Anfrage abzubrechen:
controller.abort();

Best Practices für den Umgang mit AbortError:

Abbrechen von Timern mit AbortSignal

Das AbortSignal kann auch verwendet werden, um mit setTimeout oder setInterval erstellte Timer abzubrechen. Dies erfordert etwas mehr manuelle Arbeit, da die eingebauten Timer-Funktionen AbortSignal nicht direkt unterstützen. Sie müssen eine benutzerdefinierte Funktion erstellen, die auf das Abbruchsignal lauscht und den Timer löscht, wenn es ausgelöst wird.


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

  return timeoutPromise;
}

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


cancellableTimeout(() => {
  console.log('Timeout ausgeführt');
}, 2000, signal)
.then(() => console.log("Timeout erfolgreich beendet"))
.catch(err => console.log(err));

// Um das Timeout abzubrechen:
controller.abort();

Erklärung:

  1. Die cancellableTimeout-Funktion nimmt einen Callback, eine Verzögerung und ein AbortSignal als Argumente.
  2. Sie richtet ein setTimeout ein und speichert die Timeout-ID.
  3. Sie fügt dem AbortSignal einen Event-Listener hinzu, der auf das abort-Ereignis lauscht.
  4. Wenn das abort-Ereignis ausgelöst wird, löscht der Event-Listener das Timeout und weist die Promise zurück.

Abbrechen von Event-Listenern

Ähnlich wie bei Timern können Sie AbortSignal verwenden, um Event-Listener abzubrechen. Dies ist besonders nützlich, wenn Sie Event-Listener entfernen möchten, die mit einer Komponente verbunden sind, die unmounted wird.


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

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

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

// Um den Event-Listener abzubrechen:
controller.abort();

Erklärung:

  1. Wir übergeben das signal als Option an die addEventListener-Methode.
  2. Wenn controller.abort() aufgerufen wird, wird der Event-Listener automatisch entfernt.

AbortController in React-Komponenten

In React können Sie AbortController verwenden, um asynchrone Operationen abzubrechen, wenn eine Komponente unmounted wird. Dies ist unerlässlich, um Speicherlecks und Fehler zu vermeiden, die durch die Aktualisierung von unmounted Komponenten verursacht werden. Hier ist ein Beispiel mit dem 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 abgebrochen');
        } else {
          console.error('Fetch-Fehler:', error);
        }
      }
    }

    fetchData();

    return () => {
      controller.abort(); // Bricht die Fetch-Anfrage ab, wenn die Komponente unmounted wird
    };
  }, []); // Leeres Abhängigkeits-Array stellt sicher, dass dieser Effekt nur einmal beim Mounten ausgeführt wird

  return (
    
{data ? (

Daten: {JSON.stringify(data)}

) : (

Laden...

)}
); } export default MyComponent;

Erklärung:

  1. Wir erstellen einen AbortController innerhalb des useEffect-Hooks.
  2. Wir übergeben das signal an die fetch-Anfrage.
  3. Wir geben eine Aufräumfunktion aus dem useEffect-Hook zurück. Diese Funktion wird aufgerufen, wenn die Komponente unmounted wird.
  4. Innerhalb der Aufräumfunktion rufen wir controller.abort() auf, um die Fetch-Anfrage abzubrechen.

Fortgeschrittene Anwendungsfälle

Verketten von AbortSignals

Manchmal möchten Sie vielleicht mehrere AbortSignals miteinander verketten. Zum Beispiel könnte eine übergeordnete Komponente Operationen in ihren untergeordneten Komponenten abbrechen müssen. Sie können dies erreichen, indem Sie einen neuen AbortController erstellen und dessen Signal sowohl an die übergeordnete als auch an die untergeordnete Komponente übergeben.

Verwendung von AbortController mit Drittanbieter-Bibliotheken

Wenn Sie eine Drittanbieter-Bibliothek verwenden, die AbortSignal nicht direkt unterstützt, müssen Sie möglicherweise Ihren Code an den Abbruchmechanismus der Bibliothek anpassen. Dies könnte bedeuten, die asynchronen Funktionen der Bibliothek in Ihre eigenen Funktionen zu wrappen, die das AbortSignal behandeln.

Vorteile der Verwendung von AbortController

Browserkompatibilität

AbortController wird von modernen Browsern wie Chrome, Firefox, Safari und Edge weitgehend unterstützt. Sie können die Kompatibilitätstabelle in den MDN Web Docs für die neuesten Informationen überprüfen.

Polyfills

Für ältere Browser, die AbortController nicht nativ unterstützen, können Sie ein Polyfill verwenden. Ein Polyfill ist ein Stück Code, das die Funktionalität einer neueren Funktion in älteren Browsern bereitstellt. Es gibt mehrere AbortController-Polyfills online.

Fazit

Die AbortController-Schnittstelle ist ein leistungsstarkes Werkzeug zur Verwaltung asynchroner Operationen in JavaScript. Durch die Verwendung von AbortController können Sie saubereren, performanteren und robusteren Code schreiben, der Abbrüche elegant handhabt. Egal, ob Sie Daten von APIs abrufen, Timer setzen oder Event-Listener verwalten, AbortController kann Ihnen helfen, die Gesamtqualität Ihrer Webanwendungen zu verbessern.

Weiterführende Lektüre