한국어

JavaScript의 AbortController를 사용하여 fetch 요청, 타이머 등과 같은 비동기 작업을 효과적으로 취소하는 방법을 배우고 더 깔끔하고 성능이 뛰어난 코드를 확보하세요.

JavaScript AbortController: 비동기 작업 취소 마스터하기

최신 웹 개발에서 비동기 작업은 어디에나 존재합니다. API에서 데이터를 가져오고, 타이머를 설정하고, 사용자 상호 작용을 처리하는 작업은 독립적으로 실행되고 잠재적으로 장시간 지속되는 코드를 포함하는 경우가 많습니다. 그러나 완료되기 전에 이러한 작업을 취소해야 하는 시나리오가 있습니다. 바로 이럴 때 JavaScript의 AbortController 인터페이스가 도움이 됩니다. DOM 작업 및 기타 비동기 작업에 취소 요청을 알리는 깔끔하고 효율적인 방법을 제공합니다.

취소의 필요성 이해

기술적인 세부 사항을 살펴보기 전에 비동기 작업 취소가 왜 중요한지 이해해 보겠습니다. 다음과 같은 일반적인 시나리오를 고려해 보세요.

AbortController 및 AbortSignal 소개

AbortController 인터페이스는 비동기 작업 취소 문제를 해결하기 위해 설계되었습니다. 두 가지 주요 구성 요소로 구성됩니다.

기본 사용법: Fetch 요청 취소

fetch 요청을 취소하는 간단한 예제부터 시작하겠습니다.


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

설명:

  1. AbortController 인스턴스를 만듭니다.
  2. controller에서 연결된 AbortSignal을 가져옵니다.
  3. signalfetch 옵션에 전달합니다.
  4. 요청을 취소해야 하는 경우 controller.abort()를 호출합니다.
  5. .catch() 블록에서 오류가 AbortError인지 확인합니다. 그렇다면 요청이 취소된 것입니다.

AbortError 처리

controller.abort()가 호출되면 fetch 요청이 AbortError와 함께 거부됩니다. 코드에서 이 오류를 적절하게 처리하는 것이 중요합니다. 그렇지 않으면 처리되지 않은 프로미스 거부 및 예기치 않은 동작이 발생할 수 있습니다.

다음은 오류 처리가 포함된 더욱 강력한 예제입니다.


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

AbortError 처리 모범 사례:

AbortSignal을 사용하여 타이머 취소

AbortSignalsetTimeout 또는 setInterval로 생성된 타이머를 취소하는 데 사용할 수도 있습니다. 기본 제공 타이머 기능은 AbortSignal을 직접 지원하지 않으므로 약간 더 수동적인 작업이 필요합니다. abort 신호를 수신하고 트리거될 때 타이머를 지우는 사용자 지정 함수를 만들어야 합니다.


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

설명:

  1. cancellableTimeout 함수는 콜백, 지연 및 AbortSignal을 인수로 사용합니다.
  2. setTimeout을 설정하고 시간 초과 ID를 저장합니다.
  3. abort 이벤트를 수신하는 AbortSignal에 이벤트 리스너를 추가합니다.
  4. abort 이벤트가 트리거되면 이벤트 리스너가 시간 초과를 지우고 프로미스를 거부합니다.

이벤트 리스너 취소

타이머와 유사하게 AbortSignal을 사용하여 이벤트 리스너를 취소할 수 있습니다. 이는 언마운트되는 컴포넌트와 연결된 이벤트 리스너를 제거하려는 경우 특히 유용합니다.


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

설명:

  1. signaladdEventListener 메서드에 옵션으로 전달합니다.
  2. controller.abort()가 호출되면 이벤트 리스너가 자동으로 제거됩니다.

React 컴포넌트의 AbortController

React에서 AbortController를 사용하여 컴포넌트가 언마운트될 때 비동기 작업을 취소할 수 있습니다. 이는 메모리 누수와 언마운트된 컴포넌트 업데이트로 인한 오류를 방지하는 데 필수적입니다. 다음은 useEffect 후크를 사용하는 예입니다.


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;

설명:

  1. useEffect 후크 내에서 AbortController를 만듭니다.
  2. signalfetch 요청에 전달합니다.
  3. useEffect 후크에서 정리 함수를 반환합니다. 이 함수는 컴포넌트가 언마운트될 때 호출됩니다.
  4. 정리 함수 내에서 controller.abort()를 호출하여 fetch 요청을 취소합니다.

고급 사용 사례

AbortSignal 연결

경우에 따라 여러 AbortSignal을 함께 연결할 수 있습니다. 예를 들어 자식 컴포넌트에서 작업을 취소해야 하는 상위 컴포넌트가 있을 수 있습니다. 새 AbortController를 만들고 해당 신호를 상위 및 자식 컴포넌트에 모두 전달하여 이를 달성할 수 있습니다.

타사 라이브러리와 함께 AbortController 사용

AbortSignal을 직접 지원하지 않는 타사 라이브러리를 사용하는 경우 라이브러리의 취소 메커니즘과 함께 작동하도록 코드를 조정해야 할 수 있습니다. 여기에는 AbortSignal을 처리하는 자체 함수에서 라이브러리의 비동기 함수를 래핑하는 작업이 포함될 수 있습니다.

AbortController 사용의 이점

브라우저 호환성

AbortController는 Chrome, Firefox, Safari 및 Edge를 포함한 최신 브라우저에서 널리 지원됩니다. 최신 정보는 MDN Web Docs에서 호환성 표를 확인할 수 있습니다.

Polyfill

AbortController를 기본적으로 지원하지 않는 이전 브라우저의 경우 Polyfill을 사용할 수 있습니다. Polyfill은 이전 브라우저에서 최신 기능의 기능을 제공하는 코드 조각입니다. 온라인에서 사용할 수 있는 여러 AbortController Polyfill이 있습니다.

결론

AbortController 인터페이스는 JavaScript에서 비동기 작업을 관리하는 강력한 도구입니다. AbortController를 사용하면 취소를 정상적으로 처리하는 더 깔끔하고 성능이 뛰어나며 강력한 코드를 작성할 수 있습니다. API에서 데이터를 가져오거나, 타이머를 설정하거나, 이벤트 리스너를 관리하는 등 AbortController는 웹 애플리케이션의 전반적인 품질을 향상시키는 데 도움이 될 수 있습니다.

추가 자료