긴 애니메이션 프레임 API

W3C 최초 공개 작업 초안,

이 문서에 대한 자세한 정보
이 버전:
https://www.w3.org/TR/2026/WD-long-animation-frames-20260428/
최신 공개 버전:
https://www.w3.org/TR/long-animation-frames/
편집자 초안:
https://w3c.github.io/long-animation-frames/
이력:
https://www.w3.org/standards/history/long-animation-frames/
테스트 스위트:
https://wpt.fyi/results/long-animation-frames
피드백:
GitHub
명세 내 인라인
편집자:
(Google)

초록

이 문서는 웹 페이지 작성자가 "긴 애니메이션 프레임"의 존재를 감지하는 데 사용할 수 있는 API를 정의한다. 긴 애니메이션 프레임은 UI 스레드를 장시간 독점하고 다른 중요한 작업(예: 사용자 입력에 반응)이 실행되는 것을 막는다.

이 문서의 상태

이 절은 이 문서가 공개된 시점의 상태를 설명한다. 현재 W3C 공개 문서 목록과 이 기술 보고서의 최신 개정판은 W3C 표준 및 초안 색인에서 확인할 수 있다.

이 문서는 Web Performance Working Group에 의해 권고안 단계를 사용하여 최초 공개 작업 초안으로 공개되었다. 최초 공개 작업 초안으로 공개되었다고 해서 W3C와 그 회원들이 이를 지지한다는 뜻은 아니다.

이는 초안 문서이며 언제든지 다른 문서로 갱신, 대체 또는 폐기될 수 있다. 이 문서를 진행 중인 작업이 아닌 것으로 인용하는 것은 부적절하다.

GitHub Issues는 이 명세에 대한 논의에 선호된다.

이 문서는 2025년 8월 18일 W3C 프로세스 문서의 적용을 받는다.

이 문서는 W3C 특허 정책에 따라 운영되는 그룹에 의해 작성되었다. W3C는 이 그룹의 산출물과 관련하여 이루어진 모든 특허 공개의 공개 목록을 유지하며, 해당 페이지에는 특허를 공개하는 방법도 포함되어 있다. 개인이 필수 청구항을 포함한다고 믿는 특허에 대해 실제 지식을 가지고 있는 경우, 그 개인은 필수 청구항에 해당하는 정보를 W3C 특허 정책 제6절에 따라 공개해야 한다.

이 문서에 대해 의견을 남기려면 Long Animation Frames 저장소에 이슈를 작성하라.

1. 소개

페이지가 로드되는 동안, 그리고 이후 사용자가 페이지와 상호작용하는 동안 애플리케이션과 브라우저는 브라우저가 실행할 다양한 이벤트를 큐에 넣는다. 예를 들어 사용자 에이전트는 사용자의 활동에 기반하여 입력 이벤트를 스케줄하고, 애플리케이션은 requestAnimationFrame 및 기타 콜백을 스케줄하는 식이다. 큐에 들어가면, 브라우저는 이러한 이벤트를 하나씩 큐에서 꺼내 실행한다.

하지만 일부 작업은 긴 시간(여러 프레임)이 걸릴 수 있으며, 그런 일이 발생하면 UI 스레드가 차단되어 다른 모든 작업도 함께 차단될 수 있다. 사용자에게 이는 흔히 브라우저가 사용자 입력에 응답할 수 없는 "멈춘" 페이지로 보이며, 오늘날 웹에서 나쁜 사용자 경험의 주요 원인이다:

지연된 "time to Interactive":

페이지가 로드되는 동안, 또는 완전히 시각적으로 렌더링된 뒤에도 긴 작업은 종종 메인 스레드를 점유하여 사용자가 페이지와 상호작용하지 못하게 한다. 잘못 설계된 서드파티 콘텐츠가 빈번히 그 원인이다.

높거나 가변적인 입력 지연 시간:

중요한 사용자 상호작용 이벤트(예: 탭, 클릭, 스크롤, 휠 등)가 긴 작업 뒤에 큐잉되어, 버벅이고 예측하기 어려운 사용자 경험을 낳는다.

높거나 가변적인 이벤트 처리 지연 시간:

입력과 마찬가지로 이벤트 콜백(예: onload 이벤트 등)을 처리하는 것은 애플리케이션 업데이트를 지연시킨다.

버벅이는 애니메이션과 스크롤:

일부 애니메이션 및 스크롤 상호작용은 컴포지터 스레드와 메인 스레드 간의 조정을 필요로 한다. 긴 작업이 메인 스레드를 차단하고 있으면 애니메이션과 스크롤의 응답성에 영향을 줄 수 있다.

일부 애플리케이션과 RUM 공급자는 이미 "긴 작업"이 발생하는 경우를 식별하고 추적하려고 시도하고 있다. 예를 들어 알려진 패턴 중 하나는 짧은 주기 타이머를 설치하고 연속된 만료 사이의 경과 시간을 검사하는 것이다. 경과 시간이 타이머 주기보다 크면, 하나 이상의 긴 작업이 이벤트 루프의 실행을 지연시켰을 가능성이 높다. 이 접근 방식은 대체로 동작하지만 몇 가지 나쁜 성능상의 영향을 갖는다. 긴 작업을 감지하기 위해 폴링함으로써 애플리케이션은 정지 상태와 긴 유휴 블록을 방해한다(requestIdleCallback 참조). 이는 배터리 수명에도 나쁘며, 지연을 유발하는 것이 무엇인지(예: 퍼스트파티 코드인지 서드파티 코드인지) 알 방법도 없다.

RAIL 성능 모델은 애플리케이션이 사용자 입력에 100ms 미만으로 응답해야 한다고 제안한다(터치 이동과 스크롤의 경우 임계값은 16ms이다). 이 API의 목표는 애플리케이션이 이러한 목표를 달성하지 못하게 할 수 있는 작업에 대한 알림을 노출하는 것이다. 이 API는 50ms 이상 걸리는 작업을 노출한다. 이러한 작업이 없는 웹사이트는 100ms 이내에 사용자 입력에 응답해야 한다. 사용자 입력이 수신될 때 실행 중인 작업을 끝내는 데 50ms 미만이 걸리고, 그러한 사용자 입력에 반응하는 작업을 실행하는 데도 50ms 미만이 걸릴 것이기 때문이다.

1.1. 사용 예제

const observer = new PerformanceObserver(function(list) {
    for (const entry of list.getEntries()) {
        // 긴 작업 알림 처리:
        // 분석 및 모니터링을 위해 보고
        // ...
    }
});
// 이전 및 향후 긴 작업 알림에 대해 관찰자를 등록한다.
observer.observe({type: "long-animation-frame", buffered: true});
// 이후 긴 스크립트 실행은 관찰자에서
// "long-animation-frame" 항목을 큐에 넣고 수신하게 만든다.

// 이전 및 향후 긴 애니메이션 프레임 알림에 대해 관찰자를 등록한다.
// 이후 메인 스레드가 바쁜 긴 기간은 관찰자에서
// "long-animation-frame" 항목을 큐에 넣고 수신하게 만든다.
observer.observe({type: "long-animation-frame", buffered: true});

1.2. 긴 애니메이션 프레임과 긴 작업

긴 작업과 긴 애니메이션 프레임은 모두 혼잡과 버벅임을 측정하지만, 긴 애니메이션 프레임은 사용자가 이러한 유형의 혼잡을 어떻게 인식하는지와 더 잘 상관되는 정보를 제공한다. 이는 긴 애니메이션 프레임이 메인 스레드가 유휴 상태일 때 시작하고, 프레임이 렌더링되거나 사용자 에이전트가 렌더링할 것이 없다고 판단할 때 끝나는 시퀀스를 측정하기 때문이다.

task 용어는 어느 정도 구현 세부사항이며, 긴 애니메이션 프레임 추가는 동일한 메인 스레드 혼잡/버벅임 현상에 대해 더 사용자 중심적인 지표를 도입함으로써 이를 보완하려고 시도한다.

긴 애니메이션 프레임은 렌더링 단계가 최대 하나임이 보장되므로, 이를 사용하여 렌더링 단계 자체에 대한 추가 정보, 예를 들어 renderStartstyleAndLayoutStart를 노출할 수도 있다.

2. 긴 애니메이션 프레임 타이밍

긴 애니메이션 프레임은 지속 시간이 50ms를 초과하는 다음 발생 중 하나를 가리킨다:

긴 애니메이션 프레임 타이밍은 다음 새 인터페이스를 포함한다:

2.1. PerformanceLongAnimationFrameTiming 인터페이스

[Exposed=Window]
interface PerformanceLongAnimationFrameTiming : PerformanceEntry {
    /* Overloading PerformanceEntry */
    readonly attribute DOMHighResTimeStamp startTime;
    readonly attribute DOMHighResTimeStamp duration;
    readonly attribute DOMString name;
    readonly attribute DOMString entryType;

    readonly attribute DOMHighResTimeStamp renderStart;
    readonly attribute DOMHighResTimeStamp styleAndLayoutStart;
    readonly attribute DOMHighResTimeStamp blockingDuration;
    readonly attribute DOMHighResTimeStamp firstUIEventTimestamp;
    [SameObject] readonly attribute FrozenArray<PerformanceScriptTiming> scripts;
    [Default] object toJSON();
};

PerformanceLongAnimationFrameTiming includes PaintTimingMixin;

PerformanceLongAnimationFrameTiming프레임 타이밍 정보 타이밍 정보를 가진다.

entryType 속성의 getter 단계는 "long-animation-frame"을 반환하는 것이다.

name 속성의 getter 단계는 "long-animation-frame"을 반환하는 것이다.

startTime 속성의 getter 단계는 상대 고해상도 시간을 반환하는 것이다. 이때 this타이밍 정보시작 시간this관련 전역 객체가 주어진다.

duration 속성의 getter 단계는 지속 시간을 반환하는 것이다. 이는 thisstartTime과, 상대 고해상도 시간 사이의 지속 시간이다. 이때 this타이밍 정보종료 시간this관련 전역 객체가 주어진다.

renderStart 속성의 getter 단계는 상대 고해상도 시간을 반환하는 것이다. 이때 this타이밍 정보렌더링 업데이트 시작 시간this관련 전역 객체가 주어진다.

styleAndLayoutStart 속성의 getter 단계는 상대 고해상도 시간을 반환하는 것이다. 이때 this타이밍 정보스타일 및 레이아웃 시작 시간this관련 전역 객체가 주어진다.

firstUIEventTimestamp 속성의 getter 단계는 상대 고해상도 시간을 반환하는 것이다. 이때 this타이밍 정보첫 UI 이벤트 타임스탬프this관련 전역 객체가 주어진다.

blockingDuration 속성의 getter 단계들은 다음과 같다:

  1. sortedTaskDurations타이밍 정보작업 지속 시간으로 두고, 이를 내림차순으로 정렬한다.

  2. this타이밍 정보렌더링 업데이트 시작 시간이 0이 아니면:

    1. renderDuration지속 시간으로 둔다. 이는 thisrenderStart상대 고해상도 시간 사이의 지속 시간이다. 이때 this타이밍 정보종료 시간이 주어진다.

    2. sortedTaskDurations[0]을 renderDuration만큼 증가시킨다.

      참고: 이렇게 하면 가장 긴 작업 지속 시간 + 렌더링 지속 시간의 총 지속 시간이 >50ms인 경우 차단으로 간주된다.

  3. totalBlockingDuration을 0으로 둔다.

  4. sortedTaskDurations의 각 duration에 대해 반복하면서, duration이 50보다 크면 totalBlockingDurationduration - 50만큼 증가시킨다.

  5. totalBlockingDuration을 반환한다.

scripts 속성의 getter 단계들은 다음과 같다:

  1. scripts리스트 « »로 둔다.

  2. entryWindowthis관련 전역 객체로 둔다.

  3. scriptInfo에 대해, 즉 this프레임 타이밍 정보scripts 안의 각 scriptInfo에 대해:

    1. scriptWindowscriptInfowindow로 둔다.

    2. scriptEntrythis관련 렐름 안의 새 PerformanceScriptTiming으로 둔다. 이 객체의 타이밍 정보scriptInfo이고, 그 window attribution은 처음으로 일치하는 문장에 대응하는 값이다:

      scriptWindow가 undefined인 경우

      other

      scriptWindowentryWindow인 경우

      self

      entryWindow의 관련 Document노드 navigable조상 navigablescriptWindow의 관련 Document노드 navigable포함하는 경우

      ancestor

      scriptWindow의 관련 Document노드 navigable조상 navigableentryWindow의 관련 Document노드 navigable포함하는 경우

      descendant

      entryWindow의 관련 Document노드 navigable최상위 traversablescriptWindow의 관련 Document노드 navigable최상위 traversable인 경우

      same-page

      그 밖의 경우

      other.

    3. scriptEntryscripts추가한다.

  4. scripts를 반환한다.

2.2. PerformanceScriptTiming 인터페이스

enum ScriptInvokerType {
    "classic-script",
    "module-script",
    "event-listener",
    "user-callback",
    "resolve-promise",
    "reject-promise"
};

enum ScriptWindowAttribution {
    "self", "descendant", "ancestor", "same-page", "other"
};

[Exposed=Window]
interface PerformanceScriptTiming : PerformanceEntry {
    /* Overloading PerformanceEntry */
    readonly attribute DOMHighResTimeStamp startTime;
    readonly attribute DOMHighResTimeStamp duration;
    readonly attribute DOMString name;
    readonly attribute DOMString entryType;

    readonly attribute ScriptInvokerType invokerType;
    readonly attribute DOMString invoker;
    readonly attribute DOMHighResTimeStamp executionStart;
    readonly attribute DOMString sourceURL;
    readonly attribute DOMString sourceFunctionName;
    readonly attribute long long sourceCharPosition;
    readonly attribute DOMHighResTimeStamp pauseDuration;
    readonly attribute DOMHighResTimeStamp forcedStyleAndLayoutDuration;
    readonly attribute Window? window;
    readonly attribute ScriptWindowAttribution windowAttribution;
    [Default] object toJSON();
};

PerformanceScriptTiming은 관련 스크립트 타이밍 정보 타이밍 정보를 가진다.

PerformanceScriptTiming은 관련 ScriptWindowAttribution window attribution을 가진다.

entryType 속성의 getter 단계는 "script"를 반환하는 것이다.

name 속성의 getter 단계는 "script"를 반환하는 것이다.

invokerType 속성의 getter 단계는 this타이밍 정보호출자 유형을 반환하는 것이다.

invoker 속성의 getter 단계들은 다음과 같다:

  1. thisinvokerType에 대해 전환한다:

    "`classic-script`"
    "`module-script`"

    this타이밍 정보소스 URL을 반환한다.

    "`event-listener`"
    1. targetNamethis타이밍 정보호출자 이름으로 둔다.

    2. this타이밍 정보이벤트 대상 요소 id가 빈 문자열이 아니면: targetName을 « targetName, "#", this타이밍 정보이벤트 대상 요소 id »의 연결로 설정한다.

    3. 그렇지 않고, this타이밍 정보이벤트 대상 요소 src 속성이 빈 문자열이 아니면: targetName을 « targetName, "[src=", this타이밍 정보이벤트 대상 요소 src 속성, "]" »의 연결로 설정한다.

    4. « targetName, ".on", this타이밍 정보이벤트 유형 »의 연결을 반환한다.

    이것은 다소 맞춤형으로 느껴지므로 이름 생성에 대해 논의할 필요가 있다.

    "`user-callback`"

    this타이밍 정보호출자 이름을 반환한다.

    "`resolve-promise`"
    "`reject-promise`"
    1. this타이밍 정보호출자 이름이 빈 문자열이면:

      1. thisinvokerType이 "`resolve-promise`"이면 "`Promise.resolve`"를 반환한다.

      2. 그렇지 않으면 "`Promise.reject`"를 반환한다.

    2. invokerType이 "`resolve-promise`"이면 thenOrCatch를 "`then`"으로 두고, 그렇지 않으면 "`reject-promise`"로 둔다.

    3. « invoker name, ".", thenOrCatch »의 연결을 반환한다.

startTime 속성의 getter 단계는 상대 고해상도 시간을 반환하는 것이다. 이때 this타이밍 정보시작 시간this관련 전역 객체가 주어진다.

duration 속성의 getter 단계는 지속 시간을 반환하는 것이다. 이는 thisstartTime상대 고해상도 시간 사이의 지속 시간이다. 이때 this타이밍 정보종료 시간this관련 전역 객체가 주어진다.

executionStart 속성의 getter 단계는 this타이밍 정보실행 시작 시간이 0이면 0을 반환하고, 그렇지 않으면 상대 고해상도 시간을 반환하는 것이다. 이때 this타이밍 정보실행 시작 시간this관련 전역 객체가 주어진다.

forcedStyleAndLayoutDuration 속성의 getter 단계는 스타일과 레이아웃을 동기적으로 수행하는 데 소비된 시간을 나타내는 구현 정의 값을 반환하는 것이다. 예를 들어 getComputedStyle() 또는 getBoundingClientRect()를 호출하는 경우이다.

이것을 상호운용 가능하고 규범적으로 만드는 방법을 찾는다. 아마도 WebIDL에서 이러한 함수들을 동기식 스타일/레이아웃을 요구하는 것으로 표시할 수 있을 것이다. 또한 그것이 해결되면 타이밍 정보로 이동한다.

pauseDuration 속성의 getter 단계는 this타이밍 정보일시정지 지속 시간을 반환하는 것이다.

sourceURL 속성의 getter 단계는 this타이밍 정보소스 URL을 반환하는 것이다. sourceFunctionName 속성의 getter 단계는 this타이밍 정보소스 함수 이름을 반환하는 것이다. sourceCharPosition 속성의 getter 단계는 this타이밍 정보소스 문자 위치를 반환하는 것이다.

window 속성의 getter 단계들은 다음과 같다:

  1. windowthis타이밍 정보window에 대해 deref를 호출한 결과로 둔다.

  2. window가 undefined이면 null을 반환하고, 그렇지 않으면 window를 반환한다.

windowAttribution 속성의 getter 단계는 thiswindow attribution을 반환하는 것이다.

3. 처리 모델

참고: Long Animation Frame API를 구현하는 사용자 에이전트는 각각 Window 컨텍스트에 대해 "long-animation-frame"supportedEntryTypes에 포함해야 한다.

3.1. 프레임 타이밍 정보

프레임 타이밍 정보는 긴 애니메이션 프레임 알고리즘에서 장부 기록 세부사항으로 사용되는 구조체이다. 이는 다음 항목들을 가진다:
시작 시간
현재 작업 시작 시간
렌더링 업데이트 시작 시간
스타일 및 레이아웃 시작 시간
첫 UI 이벤트 타임스탬프
종료 시간

DOMHighResTimeStamp, 초기값은 0. 참고: 위의 모든 것은 안전하지 않으며, API를 통해 노출될 때는 거칠게 조정되어야 한다.

작업 지속 시간

DOMHighResTimeStamp리스트, 초기값은 비어 있음.

scripts

스크립트 타이밍 정보리스트, 초기값은 비어 있음.

대기 중인 스크립트

Null 또는 스크립트 타이밍 정보, 초기값은 null.

스크립트 타이밍 정보구조체이다. 이는 다음 항목들을 가진다:

호출자 유형

ScriptInvokerType.

시작 시간
종료 시간
실행 시작 시간

안전하지 않은 DOMHighResTimeStamp, 초기값은 0.

일시정지 지속 시간

밀리초 수를 나타내는 DOMHighResTimeStamp, 초기값은 0.

호출자 이름
소스 URL
소스 함수 이름
이벤트 유형
이벤트 대상 요소 id
이벤트 대상 요소 src 속성

문자열, 초기값은 빈 문자열.

소스 문자 위치

숫자, 초기값은 -1.

window

Window에 대한 WeakRef.

Document는 null 또는 프레임 타이밍 정보현재 프레임 타이밍 정보를 가지며, 초기값은 null이다.

3.2. 긴 애니메이션 프레임 보고

3.2.1. 긴 애니메이션 프레임 모니터링 {#loaf-monitoring}

Document document에 대한 가장 가까운 동일 출처 루트를 얻으려면:
  1. ancestorsdocument조상 navigable로 둔다.

  2. ancestors 안의 각 ancestorNavigable에 대해 반복한다: ancestorNavigable활성 문서출처document출처동일 출처이고, ancestorNavigable활성 문서관련 에이전트document관련 에이전트라면, ancestorNavigable활성 문서를 반환한다.

  3. document를 반환한다.

Document document에 대한 관련 프레임 타이밍 정보는 그 가장 가까운 동일 출처 루트현재 프레임 타이밍 정보이다.

DOMHighResTimeStamp unsafeTaskStartTimeDocument document가 주어졌을 때, 작업 시작 시간을 기록하려면:
  1. rootdocument가장 가까운 동일 출처 루트로 둔다.

  2. root현재 프레임 타이밍 정보가 null이면, root현재 프레임 타이밍 정보를 새 프레임 타이밍 정보로 설정한다. 그 시작 시간unsafeTaskStartTime이다.

  3. root현재 프레임 타이밍 정보현재 작업 시작 시간unsafeTaskStartTime으로 설정한다.

  4. root현재 프레임 타이밍 정보의 's 시작 시간이 0이면, root현재 프레임 타이밍 정보시작 시간unsafeTaskStartTime으로 설정한다.

DOMHighResTimeStamp unsafeTaskEndTimeDocument document가 주어졌을 때, 작업 종료 시간을 기록하려면:
  1. timingInfodocument관련 프레임 타이밍 정보로 둔다.

  2. timingInfo가 null이면 반환한다.

    참고: 이는 브라우저가 시퀀스 중에 hidden 상태가 되는 경우 발생할 수 있다.

  3. safeTaskEndTimeunsafeTaskEndTimedocument관련 전역 객체가 주어졌을 때의 상대 고해상도 시간으로 둔다.

  4. safeTaskStartTimetimingInfo현재 작업 시작 시간document관련 전역 객체가 주어졌을 때의 상대 고해상도 시간으로 둔다.

  5. safeTaskStartTimesafeTaskEndTime 사이의 지속 시간timingInfo작업 지속 시간추가한다.

  6. 사용자 에이전트가 document노드 navigable의 렌더링을 업데이트해도 시각적 효과가 없다고 판단하면:

    1. document가장 가까운 동일 출처 루트현재 프레임 타이밍 정보를 null로 설정한다.

    2. frameDuration지속 시간으로 둔다. 이는 timingInfo시작 시간global이 주어졌을 때의 상대 고해상도 시간과, unsafeTaskEndTimeglobal이 주어졌을 때의 상대 고해상도 시간 사이의 지속 시간이다.

    3. frameDuration이 50밀리초 이상이면, document, timingInfo, 및 새 [/=paint timing info=]가 주어졌을 때 긴 애니메이션 프레임 항목을 큐에 넣는다.

    참고: 실제 시각적 업데이트가 없었더라도, 관련 없는 시각적 업데이트와 겹쳤다면 차단했을 시나리오이므로 여기서 긴 애니메이션 프레임으로 표시한다.

Document documentDOMHighResTimeStamp unsafeStyleAndLayoutStart가 주어졌을 때, 렌더링 시간을 기록하려면:
  1. timingInfodocument관련 프레임 타이밍 정보로 둔다.

  2. timingInfo가 null이면 반환한다.

    참고: 이는 브라우저가 시퀀스 중에 hidden 상태가 되는 경우 발생할 수 있다.

  3. frameDuration지속 시간으로 둔다. 이는 timingInfo시작 시간global이 주어졌을 때의 상대 고해상도 시간과, global이 주어졌을 때의 현재 고해상도 시간 사이의 지속 시간이다.

  4. frameDuration이 50밀리초보다 작으면, document가장 가까운 동일 출처 루트현재 프레임 타이밍 정보를 null로 설정하고 반환한다.

  5. timingInfo렌더링 업데이트 시작 시간timingInfo현재 작업 시작 시간으로 설정한다.

  6. timingInfo스타일 및 레이아웃 시작 시간unsafeStyleAndLayoutStart로 설정한다.

Document document, 프레임 타이밍 정보 timingInfo, 및 페인트 타이밍 정보 paintTimingInfo가 주어졌을 때, 긴 애니메이션 프레임 항목을 큐에 넣으려면, document관련 렐름 안의 새 PerformanceLongAnimationFrameTiming큐에 넣는다. 이 객체의 타이밍 정보timingInfo이고, 그 페인트 타이밍 정보paintTimingInfo이다.

3.2.2. 긴 스크립트 모니터링

콜백 함수 callback환경 설정 객체 settings가 주어졌을 때, 사용자 콜백에 대한 타이밍 정보를 기록하려면: settings, "`user-callback`", 그리고 스크립트 타이밍 정보 scriptTimingInfo가 주어졌을 때의 다음 단계를 사용하여 스크립트 진입점을 생성한다:
  1. scriptTimingInfo호출자 이름callback식별자로 설정한다.

  2. callback이 주어졌을 때 scriptTimingInfo에 대해 소스 위치를 적용한다.

문자열 또는 Function handler, 환경 설정 객체 settings, 그리고 boolean repeat가 주어졌을 때, 타이머 핸들러에 대한 타이밍 정보를 기록하려면: settings, "`user-callback`", 그리고 스크립트 타이밍 정보 scriptTimingInfo가 주어졌을 때의 다음 단계를 사용하여 스크립트 진입점을 생성한다:
  1. repeat가 true이면 setTimeoutOrInterval을 "setInterval"로, 그렇지 않으면 "setTimeout"으로 둔다.

  2. scriptTimingInfo호출자 이름을 « TimerHandler:", setTimeoutOrInterval »의 연결로 설정한다.

  3. handlerFunction이면, handler가 주어졌을 때 scriptTimingInfo에 대해 소스 위치를 적용한다.

Event eventEventListener listener가 주어졌을 때, 이벤트 리스너에 대한 타이밍 정보를 기록하려면: listener관련 설정 객체, "`event-listener`", 그리고 스크립트 타이밍 정보 scriptTimingInfo프레임 타이밍 정보 frameTimingInfo가 주어졌을 때의 다음 단계를 사용하여 스크립트 진입점을 생성한다:
  1. scriptTimingInfo이벤트 유형eventtype으로 설정한다.

  2. targeteventcurrentTarget으로 둔다.

  3. targetNode이면:

    1. scriptTimingInfo호출자 이름targetnodeName으로 설정한다.

    2. targetElement이면:

      1. scriptTimingInfo이벤트 대상 요소 idtargetid로 설정한다.

      2. scriptTimingInfo이벤트 대상 요소 src 속성target과 "`src`"를 사용하여 이름으로 속성 값을 얻은 결과로 설정한다.

  4. 그렇지 않으면, scriptTimingInfo호출자 이름target의 인터페이스 이름으로 설정한다.

  5. listenercallback이 주어졌을 때 scriptTimingInfo에 대해 소스 위치를 적용한다.

  6. eventUIEvent이고, frameTimingInfo첫 UI 이벤트 타임스탬프가 0이면, frameTimingInfo첫 UI 이벤트 타임스탬프eventtimeStamp로 설정한다.

Promise promise 및 "`resolve-promise`" 또는 "`reject-promise`" type이 주어졌을 때, promise resolver에 대한 타이밍 정보를 기록하려면:
  1. promise관련 렐름설정 객체, type, 그리고 스크립트 타이밍 정보 scriptTimingInfo가 주어졌을 때의 다음 단계를 사용하여 스크립트 진입점을 생성한다:

    1. scriptTimingInfo호출자 이름promise생성 시 호출자 이름으로 설정한다.

    2. scriptTimingInfo소스 URLpromise생성 시 스크립트 URL로 설정한다.

스크립트 타이밍 정보 scriptTimingInfo, 스크립트 script, 그리고 URL-or-null url이 주어졌을 때, 스크립트 블록에 대한 소스 URL을 설정하려면:
  1. url이 null이면 반환한다.

  2. url스킴이 "`http`" 또는 "`https`"이면, scriptTimingInfo소스 URLscript기준 URL로 설정한다.

  3. 그렇지 않고, url스킴이 "`blob`" 또는 "`data`"이면, scriptTimingInfo소스 URL을 « url스킴, ":"" »의 연결로 설정한다.

스크립트 scriptURL-or-null originalSourceURL가 주어졌을 때, classic script 생성 시간을 기록하려면:
  1. script설정 객체, "`classic-script`", 그리고 스크립트 타이밍 정보 scriptTimingInfo가 주어졌을 때의 다음 단계를 사용하여 스크립트 진입점을 생성한다: scriptTimingInfo, script, 및 originalSourceURL가 주어졌을 때 스크립트 블록에 대한 소스 URL을 설정한다.

classic script script가 주어졌을 때, classic script 실행 시작 시간을 기록하려면:
  1. settingsscript설정 객체로 둔다.

  2. scriptmuted errors가 true이면 반환한다.

  3. settingsWindow가 아니면 반환한다.

  4. documentsettingsdocument로 둔다.

  5. frameTimingInfodocument관련 프레임 타이밍 정보로 둔다.

  6. frameTimingInfo가 null이거나 frameTimingInfo대기 중인 스크립트가 null이 아니면 반환한다.

  7. Assert: frameTimingInfo대기 중인 스크립트호출자 유형은 "`classic-script`"이다.

  8. frameTimingInfo대기 중인 스크립트실행 시작 시간안전하지 않은 공유 현재 시간으로 설정한다.

모듈 스크립트 script가 주어졌을 때, 모듈 스크립트 실행 시작 시간을 기록하려면: script설정 객체, "`module-script`", 그리고 스크립트 타이밍 정보 scriptTimingInfo가 주어졌을 때의 다음 단계를 사용하여 스크립트 진입점을 생성한다:
  1. scriptTimingInfo실행 시작 시간scriptscriptTimingInfo시작 시간으로 설정한다.

  2. scriptTimingInfo, script, 및 script기준 URL이 주어졌을 때 스크립트 블록에 대한 소스 URL을 설정한다.

환경 설정 객체 settings, ScriptInvokerType invokerType, 그리고 steps가 주어졌을 때, 스크립트 진입점을 생성하려면, 여기서 steps스크립트 타이밍 정보와 선택적 프레임 타이밍 정보를 받는 알고리즘이다:
  1. settingsWindow가 아니면 반환한다.

  2. documentsettingsdocument로 둔다.

  3. document완전히 활성이 아니거나 hidden이면, 반환한다.

  4. frameTimingInfodocument관련 프레임 타이밍 정보로 둔다.

  5. frameTimingInfo가 null이면 반환한다.

  6. frameTimingInfo대기 중인 스크립트가 null이 아니면 반환한다.

  7. scriptTimingInfo를 새 스크립트 타이밍 정보로 둔다. 그 시작 시간안전하지 않은 공유 현재 시간이고, 그 호출자 유형invokerType이다.

  8. scriptTimingInfoframeTimingInfo가 주어졌을 때 steps를 실행한다.

  9. scriptTimingInfowindowsettings로 설정한다.

  10. frameTimingInfo대기 중인 스크립트scriptTimingInfo로 설정한다.

마이크로태스크 체크포인트에 대한 타이밍 정보를 기록하려면:
  1. script실행 중인 스크립트로 둔다.

  2. settingsscript설정 객체로 둔다.

  3. documentsettingsdocument로 둔다.

  4. document완전히 활성이 아니거나 hidden이면, 반환한다.

  5. frameTimingInfodocument관련 프레임 타이밍 정보로 둔다.

  6. scriptTimingInfoframeTimingInfo대기 중인 스크립트로 둔다.

  7. frameTimingInfo대기 중인 스크립트를 null로 설정한다.

  8. scriptTimingInfo가 null이면 반환한다.

  9. scriptTimingInfo종료 시간안전하지 않은 공유 현재 시간으로 설정한다.

  10. scriptclassic script이고 그 muted errors가 true이면:

    1. scriptTimingInfo소스 URL을 빈 문자열로 설정한다.

    2. scriptTimingInfo소스 문자 위치를 -1로 설정한다.

    3. scriptTimingInfo소스 함수 이름을 빈 문자열로 설정한다.

  11. scriptTimingInfo시작 시간scriptTimingInfo종료 시간 사이의 지속 시간이 5밀리초보다 크면, scriptTimingInfoframeTimingInfoscripts추가한다.

스크립트 타이밍 정보 scriptTimingInfo콜백 함수 또는 Function callback이 주어졌을 때, 소스 위치를 적용하려면:
  1. 사용자 에이전트는 scriptTimingInfo소스 URLcallback이 정의된 스크립트의 소스 URL로 설정할 수 있다.

  2. 사용자 에이전트는 scriptTimingInfo소스 함수 이름callback의 함수 이름으로 설정할 수 있다.

  3. 사용자 에이전트는 scriptTimingInfo소스 문자 위치callback이 정의된 문자 위치로 설정할 수 있다.

지속 시간 duration이 주어졌을 때, 일시정지 지속 시간을 기록하려면:
  1. script실행 중인 스크립트로 둔다.

  2. settingsscript설정 객체로 둔다.

  3. settingsWindow가 아니면 반환한다.

  4. documentsettingsdocument로 둔다.

  5. document완전히 활성이 아니거나 hidden이면, 반환한다.

  6. frameTimingInfodocument관련 프레임 타이밍 정보로 둔다.

  7. frameTimingInfo가 null이면 반환한다.

  8. frameTimingInfo대기 중인 스크립트가 null이면 반환한다.

  9. frameTimingInfo대기 중인 스크립트일시정지 지속 시간duration의 밀리초 값만큼 증가시킨다.

4. 기존 표준에 대한 추가

4.1. WebIDL 표준에 대한 몽키 패치

Promise 인터페이스는 관련 문자열 생성 시 호출자 이름을 가지며, 초기값은 "`Promise`"이다. Promise 인터페이스는 관련 문자열 생성 시 스크립트 URL을 가지며, 초기값은 빈 문자열이다.

Promise를 반환하기 전에, 새 promise 생성에 다음 단계를 추가한다:

  1. interfaceName을 이 promise 생성을 담당하는 인터페이스를 나타내는 문자열로 둔다.

  2. attributeName을 이 promise 생성을 담당하는 인터페이스의 속성을 나타내는 문자열로 둔다.

  3. 생성된 Promise생성 시 스크립트 URL실행 중인 스크립트기준 URL로 설정한다.

  4. 사용자 에이전트는 생성된 Promise생성 시 호출자 이름을 마지막으로 알려진 « interfaceName, ".", attributeName »의 연결로 설정할 수 있다.

    이것은 꽤 애매한데, 규범적인 방식으로 이를 수행하기 어렵기 때문이다. 개선할 수 있는지, 아니면 promise 핸들러의 소스 위치가 다소 구현 정의로 남을지 확인해야 한다.

Promise p가 주어졌을 때 promise 해결에 다음 단계를 앞에 추가한다: p 및 "`resolve-promise`"가 주어졌을 때 promise resolver에 대한 타이밍 정보를 기록한다.

Promise p가 주어졌을 때 promise 거부에 다음 단계를 앞에 추가한다: p 및 "`reject-promise`"가 주어졌을 때 promise resolver에 대한 타이밍 정보를 기록한다.

콜백 함수 호출에 다음 단계를 삽입한다. 이는 환경 설정 객체 relevant settings콜백 함수 F를 가진 뒤에 수행된다: Frelevant settings가 주어졌을 때 사용자 콜백에 대한 타이밍 정보를 기록한다.

5. 보안 및 개인정보 보호 고려사항

Long Animation Frames API는 긴 작업의 출처에 대한 origin-safe 귀속 정보를 포함함으로써 동일 출처 정책을 준수한다. 긴 작업에는 50ms 임계값이 있다. 지속 시간은 1 ms 단위의 세분성으로만 제공된다. 이를 함께 적용하면 교차 출처 누출에 대한 적절한 보호를 제공한다.

Long Animation Frames API는 사용자가 실행한 작업의 지속 시간과 유형에 대한 타이밍 정보뿐 아니라, 함수 호출을 유발한 브라우징 컨텍스트 같은 귀속 정보도 제공한다. 이는 공격자가 사용자 동작을 추측하거나 사용자를 식별하기 위해 부채널 타이밍 공격을 수행할 수 있게 할 수 있다. 예를 들어 긴 스크립트 뒤에 긴 렌더가 이어지는 패턴을 조합하여 사용자가 소셜 위젯과 상호작용했는지 추측할 수 있다. 자세한 함수 호출 귀속은 사용자의 동작을 판단하는 데 사용될 수 있다.

5.1. 관찰자에게 무엇이 노출되는가?

최상위 페이지 안의 모든 관찰자(즉, 페이지 안의 모든 iframe과 메인 프레임)는 긴 애니메이션 프레임의 존재에 대한 알림을 받는다. 우리는 작업의 시작 시간, 지속 시간(1 ms 세분성), 그리고 원인 프레임을 가리키는 포인터를 노출한다. 이 정보는 오늘날에도 setTimeout을 사용해 더 높은 해상도로 이미 관찰할 수 있다. 공격자는 페이지의 다른 모든 것을 제거하고 취약한 교차 출처 리소스를 추가하여 setTimeout의 지연이 그 리소스에 의해 발생하도록 함으로써 이를 수행할 수 있다. 서로 다른 다른 페이지(탭 또는 창)의 관찰자는 사용자 에이전트의 아키텍처와 관계없이 알림을 받아서는 안 된다.

5.2. 고려된 공격 시나리오

고려된 타이밍 공격은 다음과 같다:

  1. 전통적인 타이밍 공격: 외부 리소스 로드 시간을 사용하여 비공개 데이터의 크기를 드러내는 것이다. 예를 들어 갤러리의 숨겨진 사진 수, 사용자 이름이 유효한지 여부 등이 있다. 예시를 참조하라.

  2. 부채널 타이밍 공격: 비디오 파싱, 스크립트 파싱, App Cache 읽기 또는 Cache API (service workers) 사용에 걸리는 시간을 이용해 사용자를 고유하게 식별하거나, 사용자의 나이, 성별, 위치, 관심사 등의 프로필을 만드는 것이다. 예를 들어, 소셜 네트워크의 상태 업데이트가 특정 인구통계(예: 20-30세 여성)로 제한될 수 있으며, permalink 페이지의 파일 크기를 사용해 사용자가 대상 인구통계에 속하는지 판단할 수 있다.

이러한 시나리오는 50ms 임계값과 교차 출처 경계를 존중하는 것, 즉 신뢰할 수 없는 교차 출처 관찰자에게 작업 유형이나 추가 귀속을 보이지 않음으로써 처리된다.

5.3. Long Animation Frames API가 노출하는 추가 정보

여러 교차 출처 문서가 동일한 이벤트 루프를 공유할 수 있으므로, 이들은 동일한 프레임 시퀀스의 일부로 렌더링되고 서로의 렌더링 시간에 영향을 줄 수도 있다. 이 때문에 이러한 타이밍은 이미 어느 정도 교차 출처에서 관찰 가능하다. 예를 들어 animation frame을 요청하고 그것이 지연되는지 관찰하는 방식이다. 다만 긴 애니메이션 프레임은 이를 더 높은 충실도로 노출한다.

이를 완화하기 위해 긴 애니메이션 프레임은 "참여하는 로컬 루트"에만 보고된다. 즉, 시퀀스에 기여한 작업 태스크와 관련된 문서, 또는 프레임의 일부로 렌더링된 문서만 긴 애니메이션 프레임을 관찰할 수 있으며, 해당 긴 애니메이션 프레임은 최상위이거나 교차 출처 부모를 가진 가장 가까운 조상에서만 사용할 수 있다.

5.4. PerformanceScriptTiming과 불투명 스크립트

PerformanceScriptTiming은 스크립트 실행에 대한 정보를 노출하므로, 그렇지 않으면 쉽게 추론할 수 없는 CORS 교차 출처 스크립트에 대한 정보를 너무 많이 노출하지 않도록 해야 한다. 이를 위해 기존의 muted errors boolean을 사용하고, 그런 경우 빈 sourceURL을 보고한다.

적합성

문서 규약

적합성 요구사항은 설명적 단언과 RFC 2119 용어의 조합으로 표현된다. 이 문서의 규범적 부분에서 핵심 단어 “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, “OPTIONAL”은 RFC 2119에 설명된 대로 해석되어야 한다. 하지만 가독성을 위해, 이 명세에서는 이러한 단어들이 항상 모두 대문자로 나타나지는 않는다.

이 명세의 모든 텍스트는 명시적으로 비규범적이라고 표시된 절, 예제, 참고를 제외하고 규범적이다. [RFC2119]

이 명세의 예제는 “예를 들어”라는 말로 소개되거나, 규범적 텍스트와 구분되도록 class="example"으로 표시된다. 다음과 같다:

이는 정보성 예제의 예이다.

정보성 참고는 “참고”라는 단어로 시작하며, 규범적 텍스트와 구분되도록 class="note"으로 표시된다. 다음과 같다:

참고, 이는 정보성 참고이다.

적합한 알고리즘

알고리즘의 일부로 명령형으로 표현된 요구사항 (예: "앞쪽 공백 문자를 모두 제거한다" 또는 "false를 반환하고 이 단계를 중단한다")은 알고리즘을 소개할 때 사용된 핵심 단어 ("must", "should", "may" 등)의 의미로 해석되어야 한다.

알고리즘이나 특정 단계로 표현된 적합성 요구사항은 최종 결과가 동등하다면 어떤 방식으로든 구현할 수 있다. 특히 이 명세에서 정의한 알고리즘은 이해하기 쉽도록 의도된 것이며 성능이 좋도록 의도된 것은 아니다. 구현자는 최적화하는 것이 권장된다.

색인

이 명세에서 정의하는 용어

참조로 정의된 용어

참고문헌

규범적 참고문헌

[CSSOM-1]
Daniel Glazman; Emilio Cobos Álvarez. CSS Object Model (CSSOM). 2021년 8월 26일. WD. URL: https://www.w3.org/TR/cssom-1/
[CSSOM-VIEW-1]
Simon Fraser; Emilio Cobos Álvarez. CSSOM View Module. 2025년 9월 16일. WD. URL: https://www.w3.org/TR/cssom-view-1/
[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[ECMASCRIPT]
ECMAScript Language Specification. URL: https://tc39.es/ecma262/multipage/
[HR-TIME-2]
Ilya Grigorik. High Resolution Time Level 2. 2019년 11월 21일. REC. URL: https://www.w3.org/TR/hr-time-2/
[HR-TIME-3]
Yoav Weiss. High Resolution Time. 2026년 3월 24일. WD. URL: https://www.w3.org/TR/hr-time-3/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[LONGTASKS-1]
Noam Rosenthal. Long Tasks API. 2026년 3월 19일. WD. URL: https://www.w3.org/TR/longtasks-1/
[PAINT-TIMING]
Ian Clelland; Noam Rosenthal. Paint Timing. 2026년 3월 24일. WD. URL: https://www.w3.org/TR/paint-timing/
[PERFORMANCE-TIMELINE]
Nicolas Pena Moreno. Performance Timeline. 2025년 5월 21일. CRD. URL: https://www.w3.org/TR/performance-timeline/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. 1997년 3월. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[UIEVENTS]
Xiaoqian Wu. UI Events. 2026년 2월 21일. WD. URL: https://www.w3.org/TR/uievents/
[URL]
Anne van Kesteren. URL Standard. Living Standard. URL: https://url.spec.whatwg.org/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. Living Standard. URL: https://webidl.spec.whatwg.org/

IDL 색인

[Exposed=Window]
interface PerformanceLongAnimationFrameTiming : PerformanceEntry {
    /* Overloading PerformanceEntry */
    readonly attribute DOMHighResTimeStamp startTime;
    readonly attribute DOMHighResTimeStamp duration;
    readonly attribute DOMString name;
    readonly attribute DOMString entryType;

    readonly attribute DOMHighResTimeStamp renderStart;
    readonly attribute DOMHighResTimeStamp styleAndLayoutStart;
    readonly attribute DOMHighResTimeStamp blockingDuration;
    readonly attribute DOMHighResTimeStamp firstUIEventTimestamp;
    [SameObject] readonly attribute FrozenArray<PerformanceScriptTiming> scripts;
    [Default] object toJSON();
};

PerformanceLongAnimationFrameTiming includes PaintTimingMixin;

enum ScriptInvokerType {
    "classic-script",
    "module-script",
    "event-listener",
    "user-callback",
    "resolve-promise",
    "reject-promise"
};

enum ScriptWindowAttribution {
    "self", "descendant", "ancestor", "same-page", "other"
};

[Exposed=Window]
interface PerformanceScriptTiming : PerformanceEntry {
    /* Overloading PerformanceEntry */
    readonly attribute DOMHighResTimeStamp startTime;
    readonly attribute DOMHighResTimeStamp duration;
    readonly attribute DOMString name;
    readonly attribute DOMString entryType;

    readonly attribute ScriptInvokerType invokerType;
    readonly attribute DOMString invoker;
    readonly attribute DOMHighResTimeStamp executionStart;
    readonly attribute DOMString sourceURL;
    readonly attribute DOMString sourceFunctionName;
    readonly attribute long long sourceCharPosition;
    readonly attribute DOMHighResTimeStamp pauseDuration;
    readonly attribute DOMHighResTimeStamp forcedStyleAndLayoutDuration;
    readonly attribute Window? window;
    readonly attribute ScriptWindowAttribution windowAttribution;
    [Default] object toJSON();
};

이슈 색인

이것은 다소 맞춤형으로 느껴지므로 이름 생성에 대해 논의할 필요가 있다.
이것을 상호운용 가능하고 규범적으로 만드는 방법을 찾는다. 아마도 WebIDL에서 이러한 함수들을 동기식 스타일/레이아웃을 요구하는 것으로 표시할 수 있을 것이다. 또한 그것이 해결되면 타이밍 정보로 이동한다.
이것은 꽤 애매한데, 규범적인 방식으로 이를 수행하기 어렵기 때문이다. 개선할 수 있는지, 아니면 promise 핸들러의 소스 위치가 다소 구현 정의로 남을지 확인해야 한다.