본문 바로가기
카테고리 없음

AbortController로 비동기 웹 요청을 부분적으로 제어하기

by klm hyeon woo 2025. 3. 18.

목차

· AbortController 사용해보기

· AbortController로 fetch 취소해보기

· AbortSignal.timeout

· AbortController로 cleanup 함수를 한번에 처리할 수 있다고?


프론트엔드 개발에서는 서버와 통신하기 위해 비동기 웹 요청을 사용해요. 하지만 비동기 웹 요청은 응답 시간과 결과 값을 예측하기 어렵기도 하고, 사이드 이펙트를 발생시키는 제어하기 힘든 요소 중 하나이기도 합니다. 이때 AbortController 객체를 사용하면 이러한 비동기 웹 요청을 부분적으로 제어할 수 있어요. AbortController는 브라우저 Web API로 비동기 웹 요청을 중단할 수 있는 기능을 제공해요. 응답 시간이 오래 걸리거나, 응답이 더 이상 필요하지 않은 경우 요청을 중단할 수 있고, 이렇게 요청을 제어하며 불필요한 서버 요청을 줄여 성능을 개선할 수 있으며 더 나은 사용자 경험을 제공할 수 있어요.

AbortController 사용해보기

AbortController는 new AbortController()를 인스턴스를 생성하여 사용하고, signal 프로퍼티로 AbortSignal를 받아서 fetch()와 같은 DOM 요청과 통신할 수 있어요.

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

signal.addEventListener('abort', () => {
	console.log('Aborted', signal.aborted);
});

setTimeout(() => {
	controller.abort();
}, 100);

controller.abort()를 실행하면 controller.signalabort 이벤트를 발생시키고 이 이벤트가 발생했다는 의미로 controller.signal.abortedtrue가 되며, 이를 실행하면 signal.aborted의 값은 true로 출력이 되어요.

AborrtController로 fetch 취소해보기

fetch()로 5초 정도 걸리는 API를 호출하는 예제라고 생각을 해보세요.

const URL = '~';
fetch(URL)
	.then((res) => {
    	console.log(res);
    }).catch((e) => {
    	console.log(e);
	});

5초 정도 걸리는 API를 호출하게 되면 당연하게도 5초 정도 후에 로그 출력이 될 것이라고 예상이 되는데요, 이 응답을 받으려면 5초 정도가 걸리지만 비즈니스 로직에서 이 요청을 받을 필요가 없어졌다면 AbortController를 통해 취소를 할 수 있어요. 간단한 GET 요청의 경우 fetch(resource)처럼 간단히 URL을 지정하여 사용할 수 있지만, fetch(resource, init) 처럼 두 번째 파라미터로 초기화 옵션을 제공할 수 있어요. 이러한 과정들을 통해 AbortSignal 인스턴스를 받고 AbortController를 이용해서 원할 때 fetch 요청을 취소할 수 있어요.

const controller = new AbortController();

setTimeout(() => {
	controller.abort();
}, 2000);

const URL = '~';
fetch(URL, { signal: controller.signal })
	.then((res) => {
    	console.log(res);
    }).catch((err) => {
    	if (err.name === 'AbortError') {
        	console.log(err);
        	return;
        }
        throw err;
    });

앞에서 AbortController를 살펴보았던 것처럼 5초 정도 걸리는 GET 요청을 fetch()로 보낸 후 2초 후에 controller.abort()를 실행하여 fetch()를 취소시켰어요. fetch()가 취소되면 AbortError라는 DOMExceiption을 던지기 떄문에 취소된 오류와 다른 오류를 구분하여 처리할 수 있다는 특징을 가지고 있어요.

AbortSignal.timeout

위의 예제들에서는 특정 시간 뒤에 abort()가 호출되도록 했지만, 요청에 타임아웃을 지정하려면 AbortSignal.timeout을 사용하는 것이 더 코드 상 간편함을 가져올 수 있어요. AbortSignal.timeout은 정적 메서드이므로 위와 같은 예제들처럼 AbortController를 생성할 필요 없이 간단히 타임아웃을 지정할 수 있어요.

정적 메서드와 동적 메서드의 차이가 뭐예요?

정적 메서드 (Static Method)
- 클래스에 속하는 메서드로, 특정 인스턴스에 종속되지 않아요
- static 키워드로 선언되며, 클래스 자체에서 호출이 가능해요
- this를 사용할 수 없고, 인스턴스의 상태에는 접근할 수 있어요
- 주로 유틸리티 함수나 인스턴스와 무관한 기능을 구현할 때 사용해요

동적 메서드 (Instance Method)
- 특정 인스턴스에 속하는 메서드로, 인스턴스를 통해 호출해야해요
- this를 사용하여 인스턴스의 상태를 참조할 수 있어요
- 클래스 내부에서 정의되지만 static 없이 선언이 되어요
const URL = '~';
fetch (URL, { signal: AbortSignal.timeout(2000) })
	.then((res) => {
    	console.log(res);
    }).catch((err) => {
    	if (err.name === 'AbortError') {
        	console.error(err);
        	return;
        }
     	throw err;
    });

위와 같이 코드를 작성하면 setTimeout 을 통해 abort 처리를 했던 것과 동일하게 작동해요.

AbortController로 cleanup 함수를 한번에 처리할 수 있다고?

사실 SPA에서 마운트 시점에 window 객체에 addEventListener을 해주면 클린업은 필수인데요, 붙여주는 이벤트 리스너가 많을수록 클린업에서 기재해야하는 함수의 양도 많아지는 것 같아요. 그러다가 우연히 링크드인의 게시글을 보게 되었는데, 아래의 방식으로도 클린업 함수를 손쉽게 처리할 수 있다고 하네요!

useEffect(() => {
  const ac = new AbortController();

  window.addEventListener("click", handleClick, { signal: ac.signal });
  window.addEventListener("change", handleChange, { signal: ac.signal });
  window.addEventListener("load", handleLoad, { signal: ac.signal });

  return () => {
    ac.abort();
  };
}, []);

레퍼런스

 

AbortController로 요청 취소하기 :: Outsider's Dev Story

[AbortController](https://developer.mozilla.org/ko/docs/Web/API/AbortController)는 웹 요청을 취소할 수 있게 해주는 기능이다. 보통 웹에서 요청을 일단 보내면 이후에 필요 없어져도 취소할 방법이 없어서...

blog.outsider.ne.kr

 

댓글