💡 이번 시간에는 웹 요청을 중단할 수 있는
AbortController
에 대해 알아보았다!
1. AbortController는 무엇일까?
1) AbortController란
AbortController
는 하나 이상의 웹 요청을 중단할 수 있는 인터페이스이다.- 대표적으로
fetch API
,Dom Event
를 특정 시점에 중단시킬 수 있다.
2) AbortController API
(1) new AbortController()
- 웹 요청을 중단할 수 있는,
AbortController
인터페이스를 생성한다.
const controller = new AbortController();
(2) AbortController.signal
- 요청을 취소할 수 있는
AbortSignal
객체 인터페이스를 반환한다.
const controller = new AbortController();
const signal = controller.signal;
- 웹 요청 API에
AbortSignal
객체의signal
값을 인자로 넘기면, 요청을 취소할 수 있는 상태가 된다.
const controller = new AbortController();
const signal = controller.signal;
// fetch 요청을 취소할 수 있는 상태
const response = await fetch(url, { signal }); // signal를 넘겨줌
- dom event에도,
signal
을 인자로 넘기면 이벤트를 취소할 수 있는 상태가 된다.
const controller = new AbortController();
const signal = controller.signal;
// dom event를 취소할 수 있는 상태
button.addEventListener('click', onClick, { signal }); // signal를 넘겨줌
(3) AbortController.abort()
abort()
를 사용하면,signal
가 할당된 웹 요청을 취소할 수 있다.
const controller = new AbortController();
controller.abort();
- 아래 코드는
abort()
를 호출해 버튼의 클릭 이벤트를 취소한 예시이다.
const controller = new AbortController();
button.addEventListener('click', onClick, { signal }); // singal이 인자로 할당됨
controller.abort(); // 호출시, button의 click 이벤트를 취소
(4) abortSignal.aborted
aborted
는abort()
가 실행되어 요청이 취소되었는지 여부를 알 수 있다.
const isAborted = abortSignal.aborted;
- 아래 코드는
aborted
여부에 따라 서로 다른 콘솔을 출력하는 예시이다.
const controller = new AbortController();
const signal = controller.signal;
// ...
if (signal.aborted) console.log('요청 취소'); // (1)
else console.log('요청 취소되지 않음!'); // (2)
- 만약
abort()
가 실행되어 요청이 취소되었다면,aborted
는true
이므로 ‘요청 취소’를 출력한다. - (1) - 그러나 요청이 취소되지 않았다면 ‘요청 취소되지 않음!’을 출력한다. - (2)
(5) abort event
abort
이벤트는 abort()
가 실행되어 요청이 중단된 경우 발생한다.
// 이벤트 접근 방법1
addEventListener('abort', (event) => { ... });
// 이벤트 접근 방법2
onabort = (event) => { ... };
3) AbortController 활용법
🤜 앞서 우리는
AbortController
는 무엇이며, 어떤 변수와 이벤트가 있는지 알아보았다.
그렇다면AbortController
은 어떤 상황에서 활용하면 좋을까? 여러 예시와 함께 살펴보자
(1) 비동기 처리 중간에 멈추기
- 비동기의 경우 중간에 호출을 멈추기 어렵다.
- 하지만 어떤 비동기 동작을 요청했는데 너무 오랜 시간이 걸려 취소해야한다면, 방법이 없을까?
- 이때 바로
AbortController
를 사용하는 것이다! AbortController
를 사용하면, 비동기 처리를 중간에 멈출 수 있다.
- 아래 예시에는 사과 이모티콘을 요청하는 버튼과 요청을 취소하는 버튼이 있다.
- 사과 요청하기 버튼은 사과 이모티콘을 화면에 띄우는 비동기 함수를 호출한다.
- 사과 이모티콘의 경우 요청 후 2초가 지나야 화면에 나타나는데, 취소 버튼을 누르면 비동기 처리를 중간에 취소할 수 있다.
See the Pen AbortController by KumJungMin (@kumjungmin) on CodePen.
비동기 취소 코드는 어떻게 구성되어 있을까? 하나씩 살펴보자
- 우선 new AbortController를 사용해
AbortController
객체를 만든다.
const controller = new AbortController();
그 다음으로 중요한 건, 사과 이모티콘을 요청하는 비동기 함수인
requestAppleIcon()
이다.function requestAppleIcon({ signal }) { return new Promise(( resolve, reject ) => { if (signal.aborted) { // (1) reject(new DOMException('Aborted', 'AbortError')); } else { setTimeout(() => { // (2) resolve('🍎 🍎 🍎 🍎'); }, 2000); } signal.addEventListener('abort', () => { // (3) reject(new DOMException('Aborted', 'AbortError')); }); }); }
signal.aborted
가true
라는 건, 이미 취소 요청이 있었다는 의미로 이때는 에러를 반환한다. - (1)signal.aborted
가false
라면 정상적으로 사과 이모티콘을 반환한다. - (2)함수 실행 도중에
abort
이벤트가 발생하면 에러를 반환한다. - (3)
requestFunc()
은 사과 요청하기 버튼 클릭시 실행하는 함수이다.
async function requestFunc() {
try {
const data = await requestAppleIcon({ signal: controller.signal }); // (4)
result.innerText = data;
} catch(e) {
if (e.message === 'Aborted') result.innerText = '중단되어 출력 불가 🙅♂️'; // (5)
}
}
requestAppleIcon()
에controller
의signal
을 인자로 넘기면 요청을 중단할 수 있는 상태가 된다. - (4)- 실행 중단 요청이 발생할 경우, 에러를 반환한다. - (5)
abortFunc()
은 요청 중단하기 버튼 클릭시 실행하는 함수이다.function abortFunc() { controller.abort(); // (6) }
controller.abort()
를 실행하며 요청을 중단시킬 수 있다. - (6)
(2) dom 이벤트 한 번만 발생시키기
- dom 이벤트의 경우,
once
로 지정하면 이벤트를 한 번만 실행시킬 수 있다.
el.addEventListener('click', function() {
alert('안녕하세요!!');
}, { once : true });
그런데
AbortController
를 사용해서도 dom이벤트를 한 번만 실행시킬 수 있다!
const button = document.getElementById('button');
const controller = new AbortController();
const { signal } = controller;
button.addEventListener('click', onClick, { signal }); // (1)
function onClick() {
console.log('clicked!');
controller.abort(); // (2)
}
- 방법은 간단한데, 우선 한 번만 실행하고 싶은 이벤트에
signal
을 인자로 넘긴다. - (1) - 그 다음 이벤트 발생시
controller.abort()
를 실행하면 이벤트를 한 번만 발동시킬 수 있다. - (2)
이렇게 코드를 작성하면 버튼을 눌러도 최초 1번만 실행된다 :)
See the Pen Event once by KumJungMin (@kumjungmin) on CodePen.
(3) 이벤트 한 번에 제거하기, removeEventListener의 대안
- 이벤트 리스너의 경우,
removeEventListener
를 하지 않으면 이벤트 리스너가 요소보다 오래 남아 메모리 누수가 발생한다. - 그렇기에 우리는 이벤트 리스너를
removeEventListener
를 사용해 제거해줘야 한다. - 그런데 여러 개의 이벤트 리스너가 있는 경우, 일일이 다
removeEventListener
로 제거해야하나? - 만약
AbortController
를 몰랐다면 아래와 같이 제거해야 했을 것이다.
// 이벤트 리스너 등록
btn1.addEventListener('click', onClick);
btn2.addEventListener('click', onClick);
btn3.addEventListener('click', onClick);
// 이벤트 리스너 제거
window.addEventListener('beforeunload', () => {
btn1.removeEventListener('click', onClick);
btn2.removeEventListener('click', onClick);
btn3.removeEventListener('click', onClick);
};
)
- 하지만
AbortController
를 사용하면,abort()
를 호출하여 한 번에 이벤트 리스너를 제거할 수 있다!
// AbortController 객체 가져오기
const controller = new AbortController();
const { signal } = controller;
// signal인자를 넘기기
btn1.addEventListener('click', onClick, { signal });
btn2.addEventListener('click', onClick, { signal });
btn3.addEventListener('click', onClick, { signal });
// abort() 호출해서 이벤트 리스너 제거하기
window.addEventListener('beforeunload', () => {
controller.abort();
};
)
이번 시간에는 AbortController를 사용해 웹 요청을 취소하는 방법에 대해 알아보았다!
우선 취소하고 싶은 웹 요청 함수에singal
변수를 인자로 넘겨야 했으며,abort()
를 실행하면 요청을 취소할 수 있었다 :)
만약 비동기 함수를 중간에 취소해야 하거나 Dom 이벤트를 한 번에 제거하고 싶다면 이 방법을 써도 좋을 듯 하다~
추가적으로 더 알아보고 싶다면, CSS-trick의 포스팅, (MDN Web Docs 문서)도 살펴보자
'개발 기술 > 개발 이야기' 카테고리의 다른 글
CSS 색상 변수에 투명도를 주는 방법(feat. js) (0) | 2023.04.09 |
---|---|
[JS] 커스텀 이벤트를 만드는 2가지 방법(Event, CustomEvent) (0) | 2023.03.05 |
[npm] package.json의 version 방식, tilde(~)와 caret(^) (0) | 2023.01.29 |
Storybook, UI 컴포넌트를 테스트하게 해줘!(feat. vite) (0) | 2023.01.15 |
리플로우, 리페인트와 브라우저 렌더링 알아보기 (2) | 2023.01.02 |
댓글