Develop Note by J.S.

[Javascript] Promise의 중단 처리 (AbortSignal) 본문

Language/Javascript

[Javascript] Promise의 중단 처리 (AbortSignal)

js-web 2024. 1. 9. 09:40
반응형

1. 무한 Pending 상태

Async Await 함수를 이용하여 비동기 로직을 구현할 때 도중에 한 Api 가 무한 pending 상태에 빠진다면 어떻게 빠져나올 것인지에 대한 고민이 필요할 것 입니다. 

async function initComponent() {
	try {
    	await testApi1(); 
        //만약 pending에서 빠져나오지 않는다면 initComponent()는 영원히 종료되지 않는다.
    	await testApi2();
    } catch (e) {
    	console.err(e);
    }
    
}

 

2. AbortSignal 사용

- 이런 문제가 발생했을 때 AbortSignal은 async await를 취소할 수 있는 방법 중 하나일 수 있습니다. 다만 취소 Trigger를 직접 지정해야함에 있어 완벽한 코드는 아닐 것 입니다. 만약 api 응답대기시간을 5초로 지정하여 abortSignal로 api를 취소 할 경우 취소 후 0.1초 뒤에 응답예정이었던 API를 취소함에 있어 결과론적이지만 사실상 네트웍 낭비라고 볼 수 있습니다. 

- 하지만 명확한 취소 시점에 대한 기준을 스스로 제시할 수 있다면 유용하게 사용될 것 입니다. 

 

1) Axios사용 시 

// main.ts
const abortController = new AbortController();
async function initComponent() {
	try {
    	await testApi1(abortController.signal); 
        //만약 pending에서 빠져나오지 않는다면 initComponent()는 영원히 종료되지 않는다.
    	await testApi2(abortController.signal);
    } catch (e) {
    	console.err(e);
    }
    
}
// vue3 - unmounted event에 abort() trigger
onUnmounted(() => {
	abortController.abort();
})



// axios.ts
import { AxiosResponse } from 'axios';

testApi1: (signal?: AbortSignal) => {
    return axios.get<AxiosResponse, void>(`/test/api`, { signal });
},

 

- Axios에 abortContoller.signal을 Setting하여 사용합니다.

- 컴포넌트의 Unmounted 시점을 중단 Trigger로 설정하여 abort() 함수를 실행합니다.

- API가 pending중이었다면 그 즉시 중단처리를 시키는 로직입니다.

- 예시로 Unmounted 시점으로 중단 조건을 걸었지만 로직에 따라 중단 시점을 잘 선택하면 유용하게 사용될 수 있습니다. 

 

- 예를들어 빠른 페이지(컴포넌트) 전환으로 인해 첫번째 페이지에서 요청한 api의 응답을 받지 않는 상태에서 두번째 페이지로 전환된 경우 기존 Api는 중단되지 않습니다. 중단시켜주지 않으면 응답 받은 이후의 로직이 메모리에 남아 동작되기 때문에 중단처리를 해주는 것이 좋습니다.

 

2) Safe 함수로 Wrapping

- 모든 Promise 함수를 safe로 묶어서 중단처리를 하는 방법입니다.

const abortController = new AbortController();

function safe(promise, signal) {
  return Promise.race([
    promise,
    new Promise((_,reject) => signal.addEventListener("abort", reject)),
  ])
}

async function initComponent() {
	try {
    	await safe(testApi1, abortController.signal); 
        //만약 pending에서 빠져나오지 않는다면 initComponent()는 영원히 종료되지 않는다.
    	await safe(testApi2, abortController.signal);
    } catch (e) {
    	console.err(e);
    }
}

// vue3 - unmounted event에 abort() trigger
onUnmounted(() => {
	abortController.abort();
})

 

 

 

 

 

참고사이트
https://developer.mozilla.org/ko/docs/Web/API/AbortController

https://velog.io/@sehyunny/await-event-horizon?utm_source=substack&utm_medium=email

반응형