requestIdleCallback()Copyright © 2025 World Wide Web Consortium. W3C® liability, trademark and permissive document license rules apply.
이 문서는 웹 페이지 작성자가 동일한 이벤트 루프를 공유하는 입력 처리, 애니메이션 및 프레임 합성 등과 같은 고우선순위 작업에 지연을 유발하지 않도록 백그라운드 작업을 협조적으로 예약할 수 있는 API를 정의합니다. 사용자 에이전트는 현재 예약된 작업, vsync 기한, 사용자 상호작용 등에 대한 정보를 기반으로 백그라운드 작업을 사용자가 인식할 수 있는 지연이나 애니메이션·입력 응답의 끊김 없이 실행시킬 수 있는 최적의 시점을 더 잘 판단할 수 있습니다. 따라서 이 API를 사용하면 브라우저가 유휴 상태일 때 적절하게 백그라운드 작업을 예약할 수 있습니다.
이 섹션은 본 문서가 발행될 당시의 상태를 설명합니다. 현재 W3C 발행물 목록과 이 기술 보고서의 최신 개정판은 W3C 표준 및 초안 인덱스에서 https://www.w3.org/TR/ 에서 확인할 수 있습니다.
웹 성능 워킹 그룹은 이 명세에 대한 테스트 스위트를 관리합니다. 워킹 그룹의 구현 보고서를 참고하시기 바랍니다. 이 문서의 구현에 관심 있는 벤더는 아래 메일링 리스트에 가입하여 토론에 참여하길 권장합니다.
이 문서는 Web Performance Working Group이 권고 절차에 따라 작업 초안으로 발행한 것입니다.
작업 초안으로 발행되었다고 해서 W3C와 그 회원의 승인을 의미하지는 않습니다.
이 문서는 초안이며 언제든지 업데이트, 대체 또는 폐기될 수 있습니다. 진행 중인 작업 외에 문서를 인용하는 것은 적절하지 않습니다.
이 문서는 W3C 특허 정책 하에서 운영 중인 그룹에서 작성되었습니다. W3C는 그룹의 산출물과 관련하여 공개된 특허 공개 목록 을 관리하며, 해당 페이지에는 특허 공개 방법에 대한 안내도 포함되어 있습니다. 특정 특허가 핵심 권리 청구(essential claim) 를 포함한다고 판단하는 경우 W3C 특허 정책 제6조에 따라 정보를 공개해야 합니다.
본 문서는 2023년 11월 3일 W3C 프로세스 문서의 적용을 받습니다.
이 섹션은 규범적이지 않습니다.
웹 페이지는 브라우저의 이벤트 루프에서 즉각적인 처리가 필요하지 않지만 수행하는 데 상당한 시간이 소요될 수 있는 계산 작업을 실행하고 싶을 때가 많습니다. 이러한 백그라운드 작업의 예로는 분석
데이터 기록, 장시간 데이터 처리 연산, 클라이언트 측 템플릿 처리 및 가까운 미래에 표시될 가능성이 있는 콘텐츠의 미리 렌더링 등이 있습니다. 이러한 작업은 입력 반응 및 requestAnimationFrame()을
사용한 스크립트 기반 애니메이션과 같은 다른 시간에 민감한 작업과 이벤트 루프를 공유해야 합니다.
이러한 백그라운드 작업은 일반적으로 setTimeout()을
사용하여 콜백을 예약하고, 해당 콜백에서 백그라운드 작업을 실행함으로써 수행됩니다.
이 방식의 단점은 스크립트 작성자가 특정 setTimeout()
콜백이 시간에 민감한지, 아니면 브라우저가 한가할 때까지 지연시켜도 되는지를 사용자 에이전트에 알릴 방법이 없다는 점입니다. 또한, 사용자 에이전트는 콜백에 얼마나 오랫동안 실행을 계속해도
시간에 민감한 작업을 지연시키거나 사용자에게 지각 가능한 딜레이를 일으키지 않을지에 대한 정보를 제공할 수 없습니다. 그 결과로, 개발자가 가장 쉽게 택하는 방법은 setTimeout()을
매우 작은 값으로 호출하여 콜백 안에서 가능한 최소한의 작업만을 처리하고, 추가 작업은 또 다른 setTimeout()
호출로 연이어 예약하는 것입니다. 이는 사용자 에이전트 이벤트 루프에 많은 소규모 작업을 게시하고 실행을 예약해야 하므로 비효율적입니다. 또한, 사용자 에이전트가 각 콜백 사이에 다른 시간에
민감한 작업을 적절히 섞어 실행하도록 기대하게 되는데, 이는 각 콜백이 얼마나 걸릴지 정확히 예측하기 어렵기 때문에 쉽지 않습니다.
이 문서에서 설명하는 API는 스크립트 작성자가 사용자 에이전트가 한가할 때 콜백을 예약하도록 요청할 수 있게 해줍니다. 사용자 에이전트는 콜백에 얼마나 오랫동안 한가할 것인지에 대한 예측값을 마감 시간(deadline)으로 제공합니다. 페이지 작성자는 이 마감 시간을 활용하여 이러한 백그라운드 작업이 애니메이션·입력 반응 등 지연에 민감한 이벤트에 영향을 주지 않도록 할 수 있습니다.
다음은 해당 API를 이용해 백그라운드 작업을 작성하는 예제입니다.
<!DOCTYPE html>
<title>requestIdleCallback을 이용한 백그라운드 작업 예약</title>
<script>
var requestId = 0;
var pointsTotal = 0;
var pointsInside = 0;
function piStep() {
var r = 10;
var x = Math.random() `*` r `*` 2 - r;
var y = Math.random() `*` r `*` 2 - r;
return (Math.pow(x, 2) + Math.pow(y, 2) < Math.pow(r, 2))
}
function refinePi(deadline) {
while (deadline.timeRemaining() > 0) {
if (piStep())
pointsInside++;
pointsTotal++;
}
currentEstimate = (4 `*` pointsInside / pointsTotal);
textElement = document.getElementById("piEstimate");
textElement.innerHTML="Pi Estimate: " + currentEstimate;
requestId = window.requestIdleCallback(refinePi);
}
function start() {
requestId = window.requestIdleCallback(refinePi);
}
function stop() {
if (requestId)
window.cancelIdleCallback(requestId);
requestId = 0;
}
</script>
<button onclick="start()">시작하려면 클릭!</button>
<button onclick="stop()">중지하려면 클릭!</button>
<div id="piEstimate">시작되지 않음</div>
이 섹션은 규범적이지 않습니다.
입력 처리, 렌더링 및 합성 과정이 프레임 단위로 완료된 후, 사용자 에이전트의 메인 스레드는 다음 프레임이 시작되거나, 대기 중이던 다른 작업이 실행 자격을 얻거나, 사용자 입력이 수신될 때까지
자주 유휴 상태가 됩니다. 이 명세는 requestIdleCallback() API를
통해 이러한 유휴 시간 동안 콜백 실행을 예약하는 수단을 제공합니다.
requestIdleCallback() API를
통해 게시된 콜백은 사용자 에이전트가 정의한 유휴 기간에 실행 자격을 얻습니다. 유휴 콜백이 실행될 때, 현재 유휴 기간의 끝을 나타내는 마감 시간이 주어집니다. 유휴 기간이 무엇으로
간주되는가는 사용자 에이전트에 의해 정의되지만, 일반적으로 브라우저가 유휴할 것으로 예상되는 조용한 시기에 발생하는 것으로 기대됩니다.
유휴 기간의 예로는 액티브 애니메이션 중 프레임이 화면에 커밋되고 다음 프레임의 처리가 시작되기 전까지의 시간(아래 그림 1 참조)이 있습니다. 이러한 유휴 기간은 액티브 애니메이션이나 화면 갱신 중 자주 발생하지만, 일반적으로 매우 짧습니다(예: 60Hz vsync 주기의 경우 16ms 미만).
웹 개발자는 유휴 콜백 동안 수행되는 모든 작업을 고려하여야 합니다. 일부 연산(예: promise 해소 또는 페이지 레이아웃 트리거 등)은 유휴 콜백이 종료된 후 추가 작업이 예약될 수 있습니다. 이런 경우, 애플리케이션은 데드라인이 만료되기 전에 양보(yield)해서, 이러한 작업이 다음 프레임 데드라인 전까지 수행될 수 있도록 배려해야 합니다.
다른 유휴 기간의 예로는, 사용자 에이전트에 화면 갱신이 전혀 일어나지 않고 완전히 유휴한 상황이 있습니다. 이런 경우, 사용자 에이전트는 유휴 기간의 끝을 구속할 향후 작업이 없을 수 있습니다. 예측 불가능한 작업(예: 입력 처리 등)에서 사용자 인지 가능한 지연을 방지하기 위해, 이러한 유휴 기간의 길이는 50ms로 최대치를 제한해야 합니다. 유휴 기간이 끝나면 사용자 에이전트는 계속 유휴 상태라면 또 다른 유휴 기간을 예약할 수 있습니다(그림 2 참조). 이를 통해 장시간의 유휴 기간 동안에도 백그라운드 작업이 지속될 수 있습니다.
유휴 기간 동안 사용자 에이전트는 FIFO 순서로 유휴 콜백을 실행하며, 유휴 기간이 끝나거나 실행 가능한 콜백이 더 이상 없을 때까지 실행됩니다. 따라서, 한 번의 유휴 기간에 현재 게시된 모든 유휴 콜백이 반드시 실행되는 것은 아닙니다. 남아있는 유휴 작업은 다음 유휴 기간에 실행 대상이 됩니다.
최상의 성능을 위해, 개발자들은 의미 있는 작업을 수행하지 않는 불필요한 콜백(예: requestAnimationFrame, setTimeout 등)은 제거하는 것이 권장됩니다. 이렇게 의미 없는 콜백을 반복해서 실행 대기 상태로 두는 대신, 이벤트가 실제로 발생할 때 필요한 경우에만 콜백을 예약하세요. 이런 방식은 전체적인 효율성을 높여주고, 사용자 에이전트가 대형 백그라운드 작업을 효율적으로 수행할 수 있도록 긴 유휴 콜백(최대 50ms)을 예약할 수 있게 합니다.
현재 유휴 기간이 시작되기 전에 게시된 유휴 작업만이 해당 유휴 기간 중 실행 자격을 얻습니다. 이에 따라, 한 유휴 콜백 내에서 requestIdleCallback()을 다시
호출하여 콜백을 예약하면 이 콜백은 이번 유휴 기간에 실행되지 않습니다. 이를 통해, 아래 예시와 같이 콜백이 마감 내에 완료되지 않으면 스스로 이후 유휴 기간에 재예약할 수 있고, 너무 짧은
유휴 기간에 반복 실행되는 문제를 방지할 수 있습니다:
function doWork(deadline) {
if (deadline.timeRemaining() <= 5) {
// 이 작업은 5ms 이상 걸리므로...
// 충분히 긴 데드라인일 때까지 재호출을 기다립니다.
requestIdleCallback(doWork);
return;
}
// 작업 수행...
}
다음 유휴 기간이 시작되면 새롭게 게시된 유휴 콜백이 실행 대기 유휴 콜백 목록의 맨 끝에 추가되어, 재예약된 콜백들이 라운드로빈 방식으로 실행 기회를 얻을 수 있게 하며, 이전 작업의 재게시된 콜백보다 한 번씩은 먼저 실행될 수 있습니다.
향후 버전의 이 명세는 다른 스케줄링 전략도 허용할 수 있습니다. 예를 들어, 동일 유휴 기간 내, 혹은 특정 X 밀리초 이상의 유휴 시간이 보장되는 기간 등입니다. 현재 명세는 다음 유휴 기간에 예약하는 방식만을 지원하며, 이때 콜백이 자신의 로직을 실행하거나, 또다시 다음 유휴 기간에 재예약할 수 있습니다.
사용자 에이전트가 해당 웹 페이지를 사용자에게 보이지 않는 상태로 판단하면, 장치의 전력 사용을 줄이기 위해 유휴 기간을 제한할 수 있습니다. 예를 들어, 연속적으로가 아니라 10초마다 한 번씩만 유휴 기간을 트리거하는 방식입니다.
마지막으로 주의해야 할 점은, 페이지가 무거운 상태로 구동될 때 사용자 에이전트가 유휴 CPU 시간을 전혀 할당하지 못할 수 있다는 부분입니다. 이런 경우, requestIdleCallback() API로
게시된 유휴 콜백이 무한정 지연될 수도 있습니다. 콜백이 반드시 유휴 기간 내에 실행되어야 하면서 일정 시간 내 실행이 필요하다면, 작성자는 options 인자의
timeout 속성을 requestIdleCallback()에 함께
제공할 수 있습니다. 지정한 timeout이 유휴 기간 내 콜백이 실행되기 전에 도달하면, 해당 작업은 큐에 등록되어 실행됩니다.
최대 데드라인 50ms는 [RESPONSETIME] 등의 연구에 근거하며, 사용자 입력에 100ms 이내로 응답하면 사용자의 입장에서는 즉각적인 것으로 인식한다는 결과가 있습니다. 유휴 데드라인을 50ms로 제한하면, 유휴 작업이 시작된 직후 입력이 발생하더라도 사용자 에이전트에게 50ms의 여유가 남아 있어 입력에 즉각 반응할 수 있도록 해줍니다.
비규범적(Non-normative)으로 표시된 섹션뿐 아니라, 저작 지침·도표·예제·참고 등의 내용은 모두 비규범적입니다. 그 외 이 명세서의 모든 내용은 규범적입니다.
이 문서에서 MUST, REQUIRED, SHALL, SHOULD로 표기된 용어는 BCP 14 [RFC2119] 및 [RFC8174] 의 규정에 따라, 오직 이 문서에서 대문자로 표시된 경우에만 해당 의미로 해석되어야 합니다.
이 명세서의 IDL 조각(fragment)은 MUST에 따라, 적합한 IDL 조각을 위해 반드시 따라야 합니다.
이 명세서는 하나의 적합성 클래스를 정의합니다:
Window 인터페이스 확장 섹션의 IDL 조각에 대해 적합해야 합니다.
Window
인터페이스 확장아래 IDL 조각의 partial interface는
requestIdleCallback()
연산을
Window
객체에 노출할 때 사용됩니다.
WebIDLpartial interface Window {
unsigned long requestIdleCallback(IdleRequestCallback callback, optional IdleRequestOptions options = {});
undefined cancelIdleCallback(unsigned long handle);
};
dictionary IdleRequestOptions {
unsigned long timeout;
};
[Exposed=Window] interface IdleDeadline {
DOMHighResTimeStamp timeRemaining();
readonly attribute boolean didTimeout;
};
callback IdleRequestCallback = undefined (IdleDeadline deadline);
각 Window 객체에는
다음이 존재합니다:
Window
객체가 살아 있는 한 이 값은 고유해야 합니다.requestIdleCallback(callback, options)
이
주어진 IdleRequestCallback
및 선택적 IdleRequestOptions와 함께 호출되면, 사용자 에이전트는
반드시 다음 절차를 수행해야 합니다:
Window
객체로 둡니다.다음 단계는 병렬로 실행되며, 선택적 timeout 속성이 제공된 경우 setTimeout()과 유사하게
타이머를 큐에 넣습니다. 이 시점부터 유휴 콜백과 타임아웃 콜백이 경합(race)하여 서로 취소하며, 예를 들어 유휴 콜백이 먼저 예약되면 타임아웃 콜백을 취소하고,
그 반대도 마찬가지입니다.
timeout
속성이 options에 존재하며 양수인 경우:
이 부분은 사용자 에이전트가 장치 전력 최적화를 위해 타임아웃을 여유 있게 조정할 수 있도록 한 것입니다. 예를 들어, 일부 프로세서는 저전력 모드에서 타이머 정밀도가 낮아집니다. 이런 경우, 사용자 에이전트는 더 정확한 모드 대신 이 일정에 맞추어 타이머를 느리게 운용할 수 있습니다.
requestIdleCallback()
은 항상 단일 콜백만 예약하며, 이는 단일 유휴 기간 내에 실행됩니다. 콜백이 주어진 deadline 전에 작업을 완료하지 못하면 그
안에서
requestIdleCallback()
을 반복 호출해 이후 콜백을 예약할 수 있으며, 즉시 종료하여 이벤트 루프에 제어권을 반환해야
합니다.
cancelIdleCallback()
메서드는 이전에 예약된 유휴 콜백 요청을 취소하는 데 사용합니다.
cancelIdleCallback(handle)
이 호출될 때, 사용자 에이전트는
반드시 다음 절차를 실행해야 합니다:
Window
객체로 둡니다.cancelIdleCallback()
은 window의 유휴
요청 콜백 리스트 또는 실행
가능한 유휴 콜백 리스트 항목 모두에 대해 호출될 수 있습니다.
어느 경우든 목록에서 제거하여 콜백이 실행되지 않도록 해야 합니다.
각 IdleDeadline에는 데드라인 시간 가져오기 알고리즘이
있습니다. 이는 마감 시점의 절대 시간을 밀리초 단위의 DOMHighResTimeStamp
로 반환합니다. 데드라인은 처음에는 0을 반환하도록 설정됩니다.
timeRemaining() 메서드를
IdleDeadline 객체에서 호출 시, 반드시 마감 이전까지 남은 시간을 DOMHighResTimeStamp로
반환해야 하며,
해당 값은 측정을 허용하면서 타이밍 공격을 방지할 정도의 정밀도를 가져야 합니다—자세한 내용은 [HR-TIME]의
"프라이버시/보안" 항목 참조. 계산 방법은 다음과 같습니다:
DOMHighResTimeStamp
로서 현 시점의 고해상도 시간을 밀리초 단위로
나타낸 값을 둡니다.
IdleDeadline의 데드라인 시간 가져오기 수행 결과로 둡니다.각 IdleDeadline에는 timeout이 있으며,
초깃값은 false입니다.
didTimeout
getter는 반드시
timeout
값을 반환해야 합니다.
유휴
콜백 타임아웃 알고리즘 은
timeout을 true로 설정함으로써, 콜백이 유휴 기간 밖에서 실행되고,
등록 당시 전달받은 IdleRequestOptions의 timeout을 초과한 경우임을
나타냅니다.
유휴 기간을 시작하다는 Window
window와
getDeadline을 받아 DOMHighResTimeStamp를
반환하는 알고리즘이다:
[HR-TIME]
이 알고리즘은 이벤트 루프 처리 모델 에 의해 이벤트 루프가 유휴 상태임을 판단할 때 호출된다.
지금부터 마감시간까지의 구간을 유휴 기간이라 한다. 어떤 Window에도
한 번에 오직 하나의 유휴 기간만 활성일 수 있다.
유휴 기간은 사용자 에이전트가 유휴 상태가 아니라고 판단하면 일찍 종료될 수 있다. 그러한 경우, 다음 유휴 기간은 deadline 이후까지 시작할 수
없다.
유휴
콜백 호출 알고리즘은 Window
window와
getDeadline을 받아 DOMHighResTimeStamp를
반환하는 알고리즘이다:
[HR-TIME].
IdleDeadline으로 두고,
그 마감시간 얻기 알고리즘은 getDeadline으로 둔다.
report"로 수행한다.
사용자 에이전트는 deadline이 아직 도달하지 않았더라도(1단계 반환) 유휴 기간을 미리 종료할 수 있다. 예시로, 더 높은 우선순위 작업이 실행 가능해졌다고 판단할 경우가 있다.
유휴 콜백 타임아웃 알고리즘은 다음과 같다:
IdleDeadline으로 두고,
마감시간 얻기 알고리즘을 now를 반환하는 알고리즘으로 설정하고
timeout을 true로 설정한다.
report"로 수행한다.
유휴 콜백이 예약되면 사용자 에이전트는
유휴 상태로 유지될 것으로 예상하는 시간이 얼마나 되는지에 대한 추정치를 제공합니다. 이 정보는
해당 프레임 내에서 다른 애플리케이션 작업 및 관련 브라우저 작업에 걸리는 시간을
추정하는 데 사용할 수 있습니다. 그러나 개발자는 이미 다른 방법으로도 이 정보에 접근할 수 있습니다.
예를 들어 requestAnimationFrame을 통해 프레임의 시작을 표시하고,
다음 프레임의 시간을 추정한 뒤, 그 정보를 사용하여 어떤 콜백 내에서든
"남은 시간"을 계산할 수 있습니다.
캐시 및 통계적 핑거프린팅 공격을 완화하기 위해, IdleDeadline 인터페이스가 반환하는 시간 예측의 정밀도는
정밀도
감소(coarsen)가 이루어져야 하며,
크로스
오리진 격리 기능에 따라 조정하여,
이 API가 다른 웹 노출 타이머 이상으로 정보를 노출하지 않게 해야 한다. [HR-TIME]
추후 작성 예정
이 명세서의 편집자들은 다음 분들께 기여에 대해 감사의 말씀을 드린다: Sami Kyostila, Alex Clarke, Boris Zbarsky, Marcos Caceres, Jonas Sicking, Robert O'Callahan, David Baron, Todd Reifsteck, Tobin Titus, Elliott Sprehn, Tetsuharu OHZEKI, Lon Ingram, Domenic Denicola, Philippe Le Hegaret and Anne van Kesteren.
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in: