javascript

Promise.race를 응용한 긴 비동기 작업 필터링 방법

하리하링웹 2023. 12. 22. 20:16

얼마전에 회사에서 비동기 작업의 시간에 따라 자동으로 로딩 표시를 보여주는 기능을 개발해달라는 요청을 받아 이를 개발하게 되었다.


물론 간단하게 구현할수도 있겠지만 회사 내부의 코딩 룰, 어디서 보기 힘들정도로 큰 저장소 크기, 여러번 요청할수도 있는 비동기 작업 등으로 인해 간단하게 구현하는 방식은 불가능하게 되었다.


  이러한 제약조건을 딛고 이를 구현하기 위해, 비동기 작업이 지정된 시간 이상 걸릴 경우 사용자에게 로딩 상태를 알려주는 간단하면서도 효과적인 방법을 고안했다. 이 기능의 핵심은 Promise.race를 사용하여 비동기 작업과 타임아웃을 결합시키는 것이다.

핵심 개념: Promise.race

Promise.race는 여러 프로미스 중 가장 먼저 완료되거나 실패하는 프로미스의 결과를 반환한다. 이러한 특성을 활용함으로써, 일정시간 이상의 비동기 작업을 효과적으로 감지하고 처리할 수 있다.

구현 방법

이 기능의 목표는 비동기 작업의 지연으로 인한 사용자 인터페이스의 정지를 방지, 개발자가 비동기 코드를 구현할때 이를 신경쓰지 않아도 되도록 하는것이다.

  1. 타임아웃 설정: 우선, 작업이 지정된 시간(예: 100ms)을 초과할 경우 활성화될 타임아웃 프로미스를 생성한다. 이를 위해 setTimeout 함수를 사용하고, 결과를 프로미스로 감싼다.
  2. 작업 추적: 비동기 작업이 완료되면, 설정된 타임아웃을 해제해야 한다. 이를 위해 사용자 액션 디스패처를 등록하고, 이를 통해 타임아웃을 취소할 수 있도록 한다.
  3. 사용자 피드백 제공: 타임아웃이 발생하면, 페이지의 진행 상태를 나타내는 표시기(예: 로딩 바)를 활성화하여 사용자에게 작업이 진행 중임을 알린다. 작업이 완료되면, 이 표시기를 숨긴다.

실제 적용 예

위의 전략을 실제로 적용한 예는 다음과 같다. 아래코드는 기존 코드의 많은 부분을 덜어내 기능만 있는 코드이다. 사용자가 데이터를 요청하고, 이 요청이 100ms 이내에 완료되지 않으면, 페이지에 로딩 표시가 활성화된다. 데이터 로딩이 완료되면, 이 표시기는 자동으로 사라진다.

const SHOW_PROGRESS_DURATION = 100;

class TimeoutError extends Error {
  constructor() {
    super('Timeout');
    this.name = 'TimeoutError';
  }
}

const createTimeoutPromise = (duration) => {
  return new Promise((_, reject) => {
    setTimeout(() => reject(new TimeoutError()), duration);
  });
};

const withTimeout = (asyncFunction) => async (...args) => {
  const timeoutPromise = createTimeoutPromise(SHOW_PROGRESS_DURATION);
  try {
    return await Promise.race([asyncFunction(...args), timeoutPromise]);
  } catch (e) {
    if (e instanceof TimeoutError) {
      // 타임아웃 처리 로직
      console.log('The request timed out.');
    } else {
      throw e; // 다른 오류 처리
    }
  }
};

// 예시 사용 방법
const exampleAsyncFunction = async () => {
  // 임의의 비동기 작업
};

const exampleWithTimeout = withTimeout(exampleAsyncFunction);

exampleWithTimeout().then(() => {
  // 작업 완료 후 처리
}).catch((error) => {
  // 오류 처리
});

결론

Promise.race를 활용하는 이러한 방식은 개발자의 편의성을 늘려주는 역할을 한다. 물론 다른 여러가지 패턴도 있지만 이러한 패턴도 있다는걸 알아서 나쁠것은 없을 것 같다.

추가
하지만 결국 여러가지 코드리뷰 끝에 Decorator에 붙이도록 만든 위의 방식대신 middleware 자리에Debounce로 다시 구현하게 되었다.
물론 위의 방법도 언젠가는 쓸 일이 있을 것 같다

'javascript' 카테고리의 다른 글

RequestAnimationFrame이란  (1) 2024.04.25
setTimeout에서 발생 가능한 문제들  (0) 2024.04.21
Viewport  (0) 2024.04.05
Builder를 위한 Path parser 구현 후기  (1) 2024.01.09
Code splitting시 주의해야할 점(side effect)  (1) 2023.01.15