본문 바로가기
2주차

자바스크립트 Scheduler API

by 곽지욱 2025. 4. 25.

안녕하세요 웨비 여러분 곽지욱입니다. 2주차 과제로 자바스크립트 Scheduler API 를 소개하는 글을 작성해봤습니다. 

 

웹 혹은 웹앱을 개발할 때 프로젝트의 복잡성이 높아질 수록 메인 스레드의 효율적인 관리는 JS를 사용한다면 성능 최적화의 핵심이 되는 부분입니다.

 

그 동안 보편적으로 setTimeout(0) 과 같은 기법으로 브라우저에게 작업을 잠시 양보해가며 작업을 쪼개서 실행해왔으나 이러한 방법은 우선순위나 세밀한 제어에 한계가 분명히 존재합니다.

 

이 한계를 극복하기 위해서 등장한 것이 바로 JS의 Scheduler API 입니다.

Scheduler API란?

Scheduler API는 작업의 우선순위를 명시하고, 메인 스레드에서 실행 타이밍을 보다 정밀하게 조절할 수 있도록 돕는 표준 API입니다.

기존 방식의 한계점

setTimeout(() => {
  processNextBatch();
}, 0);

 

위와 같은 방식은 브라우저의 Event Loop 에 넘겨 비동기 방식으로 처리하는 것이 가능하지만

  • 작업의 중요도 구분 불가
  • 백그라운드에서 실행할 작업과 사용자 입력 사이의 구분 부족
  • 체계적인 우선순위 불가능

과 같은 단점을 가지고 있습니다.

Scheduler API 의 핵심기능

1. scheduler.yield()

  • 현재 작업 흐름을 일시적으로 중단하고, 브라우저에게 컨트롤을 양보할 수 있습니다. 일종의 비동기 함수의 일종이며, 현재 작업을 중단하고, 브라우저가 사용자 이벤트 처리나 렌더링 같은 작업을 먼저 하도록 잠깐 쉬어주는 역할을 합니다.
function heavyTask() {
  doWorkChunk1();
  setTimeout(() => {
    doWorkChunk2();
  }, 0); // 잠깐 쉬었다 다시 실행
}
async function processLargeData() {
  for (let i = 0; i < 1000; i++) {
    processItem(i);

    if (i % 100 === 0) {
      await scheduler.yield(); // 메인 스레드 양보
    }
  }
}
  • 이렇듯 현재 실행을 중단하고, 다른 중요한 작업이 있으면 먼저 처리하게 한 뒤 다시 돌아옵니다.

2.scheduler.postTask()

  • 작업을 명시적으로 등록하고 우선순위와 취소 신호 등을 함께 설정할 수 있습니다.
await scheduler.postTask(() => {
  processNextBatch();
}, { priority: 'background' });

 

작업 우선순위 같은 경우는 Scheduler API 에서 세 가지 작업 우선순위를 지원합니다.

  1. user-blocking : 사용자 입력 처리 UI업데이트 등 즉시 처리해야 하는 작업
  2. user-visible : 사용자게에 곧 보여질 데이터 등 중요하지만 긴급하지 않은 작업
  3. background : 분석 프리페칭 등 사용자 경험에 영향 없는 작업

실제 활용 예시

async function processData(data) {
  const controller = new TaskController({ priority: 'background' });

  try {
    await scheduler.postTask(() => heavyComputation(data), {
      signal: controller.signal,
      priority: 'background'
    });
  } catch (error) {
    if (error.name !== 'AbortError') {
      console.error('Processing failed:', error);
    }
  }
}
  • heavyComputation 작업 순위를 'background'로 설정하였기에 브라우저가 다른 중요한 작업(렌더링, 사용자 입력 등) 먼저 처리한 후 실행되도록 유도합니다.
  • 사용자 인터랙션을 막지 않으면서 무거운 작업을 진행하고 싶을 때, 혹은 중간에 작업을 취소할 가능성이 있을 때 사용할 수 있습니다.

작업 중 우선순위 변경

  • 사용자 행동(이벤트)에 따라서 작업 중요도가 변하는 케이스도 존재할 수 있습니다. 이 때 TaskController 를 통해 동적으로 우선순위를 변경할 수 있습니다.
const controller = new TaskController({ priority: 'background' });

controller.signal.addEventListener('prioritychange', (e) => {
  console.log(`Changed: ${e.previousPriority} -> ${e.target.priority}`);
});

scheduler.postTask(async () => {
  await processInitialData();
  controller.setPriority('user-visible');
  await processCriticalData();
}, { signal: controller.signal });
  • 작업 도중에 controller.setPriority() 로 우선순위를 background -> user-visible로 동적으로 변경하는 코드입니다.
  • 초기에는 우선순위가 background로 설정되었으나, 우선순위가 바뀌었을 때 감지하는 이벤트 리스너인 controller.signal.addEventListener 를 설정해두었기에
  • processInitialData()가 실행되고 우선순위가 변경됩니다. 이 변경이 이루어지면서 브라우저가 controller 작업을 더 빠르게, 사용자에게 잘 보이는 작업으로 인식하게끔 만듭니다.
  • 예를 들면 초기에 리소스를 아끼고 나중에 중요한 데이터를 처리해야할 때 백그라운드로 작업을 시작하다가, 중간에 우선순위를 올리는 방법을 사용할 때 고려할 수 있습니다.

작업 중단(abort)

const controller = new TaskController();

scheduler.postTask(async () => {
  const res = await fetch('/api/data');
  return res.json();
}, { signal: controller.signal }).catch((e) => {
  if (e.name === 'AbortError') {
    console.log('작업이 중단되었습니다.');
  }
});

controller.abort(); // 언제든 중단 가능
  • 이 코드의 핵심은 예약된 작업을 중간에 중단할 수 있고, 중단된 경우에 AbortError 를 이용해서 적절한 에러처리를 수행할 수 있다는 점이에요
  • 브라우저의 스케줄러 큐에 작업을 예약하고 내부에서 fetch를 진행합니다. 이때 signal : controller.signal 을 전달해서 작업이 controller.abort() 를 호출할때 중단될 수 있도록 세팅합니다.
  • 만약 abort()에 의해 중단된다면 AbortError가 발생하고 catch 블록이 실행됩니다.

언제 Scheduler API를 사용해야 할까

  • 긴 연산을 메인 스레드를 차단 하지 않고 나눠 처리하고 싶을 때
  • 사용자의 상호작용에 영향을 주지 않도록 작업의 중요도를 조절하고 싶을 때
  • 여러 작업 간의 우선순위 체계를 도입하고 싶을 때

 

Scheduler API는 아직 실험적인 단계이지만 주요 브라우저에서는 핵심 기능을 구현하거나 하는 등의 브라우저 지원이 꾸준히 증가하고 있는 추세입니다. 

 

브라우저 지원이 확장된다면 API 개발 툴킷의 핵심이 가능성이 있으니 미리 개념을 알아둔다면 좋을 같습니다.

'2주차' 카테고리의 다른 글

자바스크립트 이벤트 루프 Event Loop  (0) 2025.04.25
js 모듈화  (0) 2025.04.25
Dialog 태그로 모달창 구현하기 !  (0) 2025.04.25
자바스크립트 동기와 비동기  (0) 2025.04.25
메모리 누수와 성능 관리  (0) 2025.04.25