목차
· 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.signal이 abort 이벤트를 발생시키고 이 이벤트가 발생했다는 의미로 controller.signal.aborted가 true가 되며, 이를 실행하면 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
댓글