이벤트 타이밍 API

W3C 워킹 드래프트,

이 문서에 대한 자세한 정보
이 버전:
https://www.w3.org/TR/2026/WD-event-timing-20261013/
최신 공개 버전:
https://www.w3.org/TR/event-timing/
에디터스 드래프트:
https://w3c.github.io/event-timing/
이전 버전:
히스토리:
https://www.w3.org/standards/history/event-timing/
테스트 스위트:
https://github.com/web-platform-tests/wpt/tree/master/event-timing
피드백:
GitHub
에디터:
(Google)
이전 에디터:
(Google)
(Google)

요약

이 문서는 웹 페이지 저자에게 사용자 상호작용으로 인해 발생하는 특정 이벤트의 지연 시간에 대한 인사이트를 제공하는 API를 정의합니다.

이 문서의 상태

이 섹션은 이 문서가 발행된 시점의 상태를 설명합니다. 현재 W3C 발행물 목록과 이 기술 보고서의 최신 버전은 W3C 표준 및 초안 색인에서 확인할 수 있습니다.

이 문서는 웹 성능 워킹 그룹에 의해 작업 초안으로 권고안 경로를 사용하여 발행되었습니다. 작업 초안으로 발행되었다고 해서 W3C 및 그 회원의 지지를 의미하지는 않습니다.

이 문서는 초안 문서로, 언제든지 다른 문서에 의해 업데이트, 대체 또는 폐기될 수 있습니다. 진행 중인 작업 외의 용도로 이 문서를 인용하는 것은 적절하지 않습니다.

GitHub 이슈를 통해 이 명세에 대한 논의를 하는 것이 권장됩니다.

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

이 문서는 W3C 특허 정책 하에 운영되는 그룹에서 작성되었습니다. W3C는 그룹 산출물과 관련된 공개 특허 공개 목록을 유지하며; 해당 페이지에는 특허 공개 방법에 대한 안내도 포함되어 있습니다. 특정 특허가 필수 청구항을 포함한다고 판단되는 경우, 해당 정보를 W3C 특허 정책 섹션 6에 따라 공개해야 합니다.

1. 소개

1.1. 개요

이 섹션은 규범적인 내용이 아닙니다.

사용자가 웹사이트와 상호작용할 때, 자신의 행동이 빠르게 웹사이트에 변화를 일으키기를 기대합니다. 실제로 연구에 따르면 100ms 이내에 처리되지 않는 모든 사용자 입력은 느리다고 간주됩니다. 따라서 입력 이벤트가 해당 기준을 달성하지 못했을 때의 성능 타이밍 정보를 노출하는 것이 중요합니다.

이벤트 지연을 모니터링하는 일반적인 방법은 이벤트 리스너를 등록하는 것입니다. 이벤트가 생성된 시점은 이벤트의 timeStamp로 얻을 수 있습니다. 추가로 performance.now()를 이벤트 핸들러 로직의 시작과 끝에서 호출할 수 있습니다. 이벤트 핸들러 시작 시점의 타임스탬프에서 하드웨어 타임스탬프를 빼면 개발자는 입력 지연—입력이 처리되기 시작하는 데 걸리는 시간—을 계산할 수 있습니다. 이벤트 핸들러 시작 시점의 타임스탬프와 끝 시점의 타임스탬프의 차이를 통해 개발자는 이벤트 핸들러에서 수행된 동기 작업의 양을 계산할 수 있습니다. 마지막으로 입력이 동기적으로 처리되는 경우, 이벤트가 처리된 후 다음 페인트까지의 기간은 사용자 경험 측정에 유용한 지표가 됩니다.

이 방식에는 여러 근본적인 문제가 있습니다. 첫째, 이벤트 리스너를 요구하면 페이지가 로드되는 아주 초기 단계에서 이벤트 지연 측정을 할 수 없습니다. 이때 리스너가 아직 등록되지 않았을 수 있습니다. 둘째, 입력 지연만 관심 있는 개발자도 원래 리스너가 없던 이벤트에 새 리스너를 추가해야 할 수 있습니다. 이는 이벤트 지연 계산에 불필요한 성능 오버헤드를 추가합니다. 마지막으로, 이 방식으로는 이벤트로 인해 발생한 비동기 작업을 측정하기 매우 어렵습니다.

이 명세는 이러한 문제를 해결하는 이벤트 지연 모니터링의 대안을 제공합니다. 사용자 에이전트가 타임스탬프를 계산하므로, 성능 측정을 위해 이벤트 리스너가 필요하지 않습니다. 이는 페이지 로드 아주 초기에 발생하는 이벤트도 포착할 수 있음을 의미합니다. 또한 느린 이벤트에 대한 가시성을 높일 수 있어, 분석 제공자가 모든 이벤트에 대해 패치 및 구독을 시도할 필요가 없습니다. 웹사이트의 성능도 불필요한 이벤트 리스너로 인한 오버헤드 없이 유지됩니다. 마지막으로, 이 명세는 개발자가 이벤트 처리 직후 발생하는 렌더링의 타이밍 정보를 상세히 얻을 수 있도록 합니다. 이는 이벤트에 의해 트리거된 웹사이트 수정의 오버헤드를 측정하는 데 유용할 수 있습니다.

1.2. 상호작용

이 절은 비규범적입니다.

사용자의 단일 Interaction (제스처라고도 합니다)은 일반적으로 여러 물리적 하드웨어 입력 이벤트로 구성됩니다. 각 물리적 입력 이벤트로 인해 사용자 에이전트가 여러 UIEvent를 발생시킬 수 있으며, 각 이벤트는 여러 사용자 정의 이벤트 리스너를 호출하거나 서로 다른 기본 동작을 유발할 수 있습니다.

예를 들어 터치스크린 기기에서 사용자의 단일 "탭" 상호작용은 실제로 일련의 물리적 입력 이벤트로 구성됩니다:

이러한 물리적 입력 이벤트는 다음과 같은 일련의 UIEvent를 발생시킬 수 있습니다:

이러한 개별 UIEvent는 각각 자체 PerformanceEventTiming 항목으로 보고될 후보가 되며, 이는 상세한 타이밍 측정에 유용합니다.

참고: pointermove 와 touchmove 는 현재 이벤트 타이밍 측정 대상으로 고려되지 않습니다.

그러나 이 명세는 관련된 PerformanceEventTiming 항목을 Interaction으로 그룹화하는 메커니즘도 정의합니다. 이는 interactionId를 통해 이루어집니다. 이 메커니즘을 사용하여 상호작용부터 다음 페인트까지(INP)라는 페이지 응답성 지표를 정의할 수 있습니다.

1.3. 최초 입력

이 섹션은 규범적인 내용이 아닙니다.

가장 첫 번째 사용자 Interaction은 사용자 경험에 불균형적으로 큰 영향을 미치며, 대체로 상대적으로 느린 경우가 많습니다.

이런 맥락에서 Event Timing API는 Window의 최초 입력에 대한 타이밍 정보를 노출합니다. 여기서 최초 입력은 interactionId가 0이 아닌 첫 번째 PerformanceEventTiming 엔트리로 정의됩니다.

대부분의 PerformanceEventTiming과 달리, 최초 입력 엔트리는 제공된 durationThreshold를 초과하지 않아도 보고되며, 기본 지속 시간 임계값인 104ms를 초과하지 않아도 버퍼링됩니다. 이 메커니즘은 First Input Delay (FID)라는 페이지 반응성 지표를 정의하는 데 사용할 수 있습니다.

이로 인해 개발자는 항상 매우 반응성이 좋은 페이지의 데이터까지 포함하여 백분위수와 성능 개선을 더 잘 측정할 수 있습니다. 이벤트 핸들러를 등록하지 않아도 됩니다.

1.4. 노출되는 이벤트

Event Timing API는 특정 이벤트에 대해서만 타이밍 정보를 노출합니다.

event가 주어졌을 때, 해당 이벤트를 이벤트 타이밍 측정 대상으로 고려해야 하는지 판단하려면 다음 단계를 실행합니다:
  1. event의 isTrusted 속성 값이 false로 설정되어 있으면 false를 반환합니다.

  2. event의 type 이 다음 중 하나이면: auxclick, click, contextmenu, dblclick, mousedown, mouseenter, mouseleave, mouseout, mouseover, mouseup, pointerover, pointerenter, pointerdown, pointerup, pointercancel, pointerout, pointerleave, gotpointercapture, lostpointercapture, touchstart, touchend, touchcancel, keydown, keypress, keyup, beforeinput, input, compositionstart, compositionupdate, compositionend, dragstart, dragend, dragenter, dragleave, dragover, drop, true를 반환합니다.

  3. false를 반환합니다.

참고: mousemove, pointermove, pointerrawupdate, touchmove, wheel, 그리고 drag 는 "연속" 이벤트이므로 제외됩니다. 현재 API에는 이러한 이벤트의 수를 세고 집계하여 항목을 기반으로 유의미한 성능 지표를 얻는 방법에 관한 충분한 지침이 없습니다. 따라서 이러한 이벤트 유형은 노출되지 않습니다.

1.5. 이벤트가 측정되는 시점

이 섹션은 규범적인 내용이 아닙니다. § 3 처리 모델 섹션에서 노출되는 정보의 상위 수준 설명입니다.

이벤트 타이밍 정보는 특정 이벤트에 대해서만, 그리고 사용자 입력과 입력 처리 이후 페인트 작업 사이의 시간 차가 특정 지속 시간 임계값을 초과할 때만 노출됩니다.

Event Timing API는 duration 값을 노출합니다. 이는 실제 사용자 입력 발생 시점(Event의 timeStamp로 추정) 부터 입력 처리 후 Event의 관련 글로벌 객체의 연결된 Document가 업데이트되는 시점까지의 시간입니다. 이 값은 8밀리초 단위로 제공됩니다.

기본적으로 Event Timing API는 duration이 104 이상일 때 버퍼링 및 노출하지만, 개발자는 PerformanceObserver를 설정하여 다른 임계값을 가진 향후 엔트리를 관찰할 수 있습니다. 이 설정은 버퍼링되는 엔트리에 영향을 주지 않으므로 buffered 플래그는 기본 임계값 이상인 과거 엔트리만 수신할 수 있도록 합니다.

Event의 delay란 브라우저가 해당 이벤트의 핸들러를 실행하려는 시점과 Event의 timeStamp의 차이입니다. 앞선 시점은 PerformanceEventTiming의 processingStart로, 뒤의 시점은 PerformanceEventTiming의 startTime으로 노출됩니다. 따라서 Event의 지연은 processingStart - startTime으로 계산할 수 있습니다.

Event Timing API는 이벤트에 리스너가 등록되어 있든 없든 엔트리를 생성합니다. 특히 최초 클릭이나 최초 키 입력은 사용자가 실제로 페이지 기능을 사용하려는 시도가 아닐 수도 있습니다; 많은 사용자가 텍스트를 선택하거나 빈 영역을 클릭해 포커스를 조정하는 행동을 합니다. 이는 이벤트 리스너가 너무 늦게 등록된 페이지의 문제를 포착하고, 리스너가 없어도 의미 있는 입력(예: hover 효과)의 성능을 포착하기 위한 설계 선택입니다. 개발자는 processingEnd - processingStart 값이 사실상 0인 엔트리를 무시함으로써 이러한 엔트리를 걸러낼 수 있습니다. processingEnd는 이벤트 디스패치 알고리즘이 종료된 시점을 나타냅니다.

1.6. 사용 예시

const observer = new PerformanceObserver(function(list, obs) {
    for (let entry of list.getEntries()) {
        // Input Delay
        const inputDelay = entry.processingStart - entry.startTime;
        // Processing duration
        const processingDuration = entry.processingEnd - entry.processingStart;
        // Presentation Delay (approximate)
        const presentationDelay = Math.max(0, entry.startTime + entry.duration - entry.processingEnd);

        // Obtain some information about the target of this event, such as the id.
        const targetId = entry.target ? entry.target.id : 'unknown-target';

        console.log(entry.entryType, entry.name, entry.duration, { inputDelay, processingDuration, presentationDelay });
    }
});
observer.observe({ type: 'first-input', buffered: true });
observer.observe({ type: 'event', buffered: true, durationThreshold: 40 });

아래 예시는 interactionId별로 각각의 이벤트 중 최대 지속 시간을 매핑하는 딕셔너리를 계산합니다. 이 딕셔너리는 나중에 집계되어 분석에 보고할 수 있습니다.

let maxDurations = {};
new PerformanceObserver(list => {
    for (let entry of list.getEntries()) {
        if (entry.interactionId > 0) {
            let id = entry.interactionId;
            if (!maxDurations[id]) {
                maxDurations[id] = entry.duration;
            } else {
                maxDurations[id] = Math.max(maxDurations[id], entry.duration);
            }
        }
    }
}).observe({ type: 'event', buffered: true, durationThreshold: 16 });

아래는 이 API를 이용해 달성할 수 있는 샘플 사용 사례입니다:

2. 이벤트 타이밍

이벤트 타이밍은 다음과 같은 인터페이스를 추가합니다:

2.1. PerformanceEventTiming 인터페이스

[Exposed=Window]
interface PerformanceEventTiming : PerformanceEntry {
    readonly attribute DOMHighResTimeStamp processingStart;
    readonly attribute DOMHighResTimeStamp processingEnd;
    readonly attribute boolean cancelable;
    readonly attribute Node? target;
    readonly attribute DOMString targetSelector;
    readonly attribute unsigned long long interactionId;
    [Default] object toJSON();
};

PerformanceEventTiming 객체는 하나의 연결된 Event에 대한 타이밍 정보를 보고합니다.

각 PerformanceEventTiming 객체는 다음과 같은 연결된 개념을 가지며, 모두 초기에 null로 설정됩니다:

target 속성의 getter는 다음 단계를 수행해야 합니다:

  1. this의 eventTarget이 문서 인수에 null을 지정한 판정에서 페인트 타이밍에 대해 노출되지 않는 경우, null을 반환한다.

  2. this의 eventTarget을 반환한다.

참고: Event Timing API를 구현하는 사용자 에이전트는 first-input과 event를 supportedEntryTypes 에 포함해야 하며, Window 컨텍스트에 적용됩니다. 이는 개발자가 이벤트 타이밍 지원 여부를 감지할 수 있게 합니다.

이 섹션의 나머지는 규범적인 내용이 아닙니다. PerformanceEventTiming 속성의 값은 § 3 처리 모델에서 설정됩니다. 이 섹션은 그 값이 어떻게 설정되는지 정보 제공 차원의 요약을 포함합니다.

PerformanceEventTiming 은 PerformanceEntry 인터페이스의 다음 속성을 확장합니다:

name
name 속성의 getter는 연결된 이벤트의 type을 제공합니다.
entryType
entryType 속성의 getter는 "event"(긴 이벤트) 또는 "first-input"(최초 사용자 상호작용) 중 하나를 반환합니다.
startTime
startTime 속성의 getter는 연결된 이벤트의 timeStamp를 반환합니다.
duration
duration 속성의 getter는 렌더링 업데이트 단계가 연결된 이벤트의 Document에서 해당 이벤트가 디스패치된 후 완료되는 다음 시점과 startTime 간의 차이를 8ms 단위로 반올림하여 반환합니다.

PerformanceEventTiming 은 다음 추가 속성을 가집니다:

processingStart
processingStart 속성의 getter는 이벤트 디스패치 알고리즘 시작 시점을 캡처한 타임스탬프를 반환합니다. 이 시점은 이벤트 핸들러가 실행되기 직전입니다.
processingEnd
processingEnd 속성의 getter는 이벤트 디스패치 알고리즘 종료 시점을 캡처한 타임스탬프를 반환합니다. 이 시점은 이벤트 핸들러 실행이 완료된 직후입니다. 해당 핸들러가 없으면 processingStart와 동일합니다.
cancelable
cancelable 속성의 getter는 연결된 이벤트의 cancelable 속성 값을 반환합니다.
target
target 속성의 getter는 연결된 이벤트의 마지막 target을 반환합니다. 이 Node가 분리되거나 섀도우 DOM에 속하지 않는 경우에만 해당합니다.
targetSelector
targetSelector 속성의 getter는 문자열을 반환하며, 이는 연관된 이벤트의 마지막 target을 식별합니다.
interactionId
interactionId 속성의 getter는 연결된 이벤트를 트리거한 사용자 Interaction을 고유하게 식별하는 숫자를 반환합니다. 이 속성은 연결된 이벤트의 type 속성 값이 다음 중 하나일 때만 0이 아닙니다:
  • 탭 또는 드래그 제스처에 속하는 pointerdown, pointerup, 또는 click, 이벤트입니다. 다만 스크롤로 이어지는 pointerdown 은 제외됩니다.

  • 사용자의 키 입력에 해당하는 keydown 또는 keyup, 이벤트입니다.

2.2. EventCounts 인터페이스

[Exposed=Window]
interface EventCounts {
    readonly maplike<DOMString, unsigned long long>;
};

EventCounts 객체는 키가 이벤트 타입 이고 값이 해당 type 의 이벤트가 디스패치된 횟수인 맵입니다. type 이 PerformanceEventTiming 엔트리( § 1.4 노출된 이벤트 참고 )에서 지원되는 이벤트만 이 맵을 통해 카운트됩니다.

2.3. Performance 인터페이스 확장

[Exposed=Window]
partial interface Performance {
    [SameObject] readonly attribute EventCounts eventCounts;
    readonly attribute unsigned long long interactionCount;
};

eventCounts 속성의 getter는 this의 관련 글로벌 객체의 eventCounts를 반환합니다.

interactionCount 속성의 getter는 this의 관련 글로벌 객체의 interactionCount를 반환합니다.

3. 처리 모델

3.1. DOM 명세 수정 사항

이 섹션은 [DOM]이 수정된 후 삭제될 예정입니다.

이벤트 디스패치 알고리즘을 다음과 같이 수정합니다.

1단계 바로 뒤에 다음 단계를 추가합니다:

  1. interactionId를 compute-interactionId 알고리즘을 event로 실행한 결과로 한다.

  2. timingEntry를 initialize-event-timing 알고리즘을 event, 현재 고해상도 시각, interactionId로 실행한 결과로 한다.

해당 알고리즘의 반환 단계 바로 앞에 다음 단계를 추가합니다:

  1. finalize-event-timing 알고리즘을 timingEntry, event, target, 현재 고해상도 시각을 인자로 실행한다.

참고: 사용자 에이전트가 이벤트 디스패치 알고리즘을 생략하는 경우에도 해당 Event에 대한 엔트리를 포함할 수 있습니다. 이 경우 processingStart 값을 추정하고 processingEnd를 그 값과 동일하게 설정합니다.

3.2. HTML 명세 수정 사항

이 섹션은 [HTML]이 수정된 후 삭제될 예정입니다.

각 Window 는 다음과 같은 개념을 가집니다:

update-the-rendering 단계에서 이벤트 루프 처리 모델 내 mark-paint-timing 호출 단계 바로 뒤에 다음 단계를 추가합니다:
  1. 각 완전히 활성화된 Document 에 대해 docs에서 dispatch-pending-event-timing-entries 알고리즘을 해당 Document에 대해 실행한다.

3.3. 성능 타임라인 명세 수정 사항

이 섹션은 [PERFORMANCE-TIMELINE-2]가 수정된 후 삭제될 예정입니다.

PerformanceObserverInit 딕셔너리에 다음 멤버가 추가됩니다:

partial dictionary PerformanceObserverInit {
    DOMHighResTimeStamp durationThreshold;
};

3.4. PerformanceEventTiming 추가 여부 결정

참고: 다음 알고리즘은 [PERFORMANCE-TIMELINE-2] 명세에서 PerformanceEventTiming 엔트리를 PerformanceObserver 버퍼 또는 성능 타임라인에 추가할지(상세 내용은 레지스트리 참고) 판단하는 데 사용됩니다.

PerformanceEventTiming entry와 PerformanceObserverInit options가 주어졌을 때, PerformanceEventTiming 추가 여부를 결정하려면 entry 및 필요에 따라 options를 인자로 다음 단계를 실행한다:
  1. entry의 entryType 속성 값이 "first-input"이면 true를 반환한다.

  2. entry의 entryType 속성 값이 "event"임을 단언한다.

  3. minDuration을 다음과 같이 계산한다:

    1. options가 없거나 options의 durationThreshold 가 없으면 minDuration을 104로 한다.

    2. 그 외에는 minDuration을 16과 options의 durationThreshold 값 중 큰 값으로 한다.

  4. entry의 duration 값이 minDuration 이상이면 true를 반환한다.

  5. 그렇지 않으면 false를 반환한다.

3.5. 상호작용 수 증가

Window window 객체에 대해 상호작용 수 증가를 요청받으면 다음 단계를 수행한다:
  1. window의 user interaction value 값을 사용자 에이전트가 선택한 작은 값만큼 증가시킨다.

  2. interactionCount를 window의 interactionCount 값으로 한다.

  3. interactionCount를 interactionCount + 1로 설정한다.

참고: user interaction value 값은 1이 아닌 사용자 에이전트가 선택한 작은 값만큼 증가시키며, 이는 개발자가 웹 애플리케이션의 실제 상호작용 횟수 카운터로 오용하지 않도록 하기 위함이다. 이 방식은 사용자 에이전트가 user interaction value를 미리 할당(예: pointerdown 시점)하고, 이후(pointercancel 등)에는 폐기할 수 있게 한다.

사용자 에이전트는 매번 작은 랜덤 정수로 증가시키거나, 상수를 사용할 수 있다. 모든 Window에 대해 공유된 글로벌 user interaction value를 사용해서는 안 되며, 이는 크로스 오리진 정보 누출을 일으킬 수 있기 때문이다.

3.6. interactionId 계산

event를 입력으로 받아 계산할 interactionId를 요청받으면 다음 단계를 실행합니다:
  1. event의 isTrusted 속성 값이 false이면 0을 반환합니다.

  2. type을 event의 type 속성 값으로 둡니다.

  3. type이 keyup, compositionstart, input, pointercancel, pointerup, click, 또는 contextmenu 중 하나가 아니면 0을 반환합니다.

    참고: keydown 및 pointerdown 은 이벤트 타이밍 확정 과정에서 보류 중으로 표시되며, 이후 후속 이벤트(예: interactionId 계산 시 갱신됩니다. keyup 및 pointerup 등).

  4. window를 event의 관련 전역 객체로 둡니다.

  5. pendingKeyDowns를 window의 보류 중인 키 누름으로 둡니다.

  6. pointerMap을 window의 포인터 상호작용 값 맵으로 둡니다.

  7. pendingPointerDowns를 window의 보류 중인 포인터 누름으로 둡니다.

  8. type이 keyup이면:

    1. event의 isComposing 속성 값이 true이면 0을 반환합니다.

    2. code를 event의 keyCode 속성 값으로 둡니다.

    3. pendingKeyDowns[code]가 존재하지 않으면 0을 반환합니다.

    4. entry를 pendingKeyDowns[code]로 둡니다.

    5. window의 상호작용 횟수를 증가시킵니다.

    6. interactionId를 window의 사용자 상호작용 값의 값으로 둡니다.

    7. entry의 interactionId를 interactionId로 설정합니다.

    8. entry를 window의 대기열에 추가할 항목에 추가합니다.

    9. pendingKeyDowns[code]를 제거합니다.

    10. interactionId를 반환합니다.

  9. type이 compositionstart이면:

    1. pendingKeyDowns의 값에 있는 각 entry에 대해:

      1. entry를 window의 대기열에 추가할 항목에 추가합니다.

    2. pendingKeyDowns를 비웁니다.

    3. 0을 반환합니다.

  10. type이 input이면:

    1. event가 InputEvent의 인스턴스가 아니면 0을 반환합니다. 참고: 이 검사는 Events 중 type이 input이지만 텍스트 콘텐츠의 변경과 관련이 없는 이벤트를 제외하기 위한 것입니다.

    2. event의 isComposing 속성 값이 false이면 0을 반환합니다.

    3. window의 상호작용 횟수를 증가시킵니다.

    4. window의 사용자 상호작용 값을 반환합니다.

  11. 그렇지 않으면 (type이 pointercancel, pointerup, click, 또는 contextmenu인 경우):

    1. pointerId를 event의 pointerId 속성 값으로 둡니다.

    2. type이 click이면:

      1. pointerMap[pointerId]가 존재하지 않으면 0을 반환합니다.

      2. value를 pointerMap[pointerId]로 둡니다.

      3. pointerMap[pointerId]를 제거합니다.

      4. value를 반환합니다.

    3. type이 pointerup, pointercancel, 또는 contextmenu인지 단언합니다.

    4. pendingPointerDowns[pointerId]가 존재하지 않으면:

      1. type이 contextmenu이면 window의 사용자 상호작용 값을 반환합니다.

      2. type이 pointerup이고 window의 컨텍스트 메뉴가 트리거되었는지를 나타내는 플래그가 true이면:

        1. window의 컨텍스트 메뉴가 트리거되었는지 나타내는 플래그를 false로 설정합니다.

        2. window의 사용자 상호작용 값을 반환합니다.

      3. 그렇지 않으면 0을 반환합니다.

    5. pointerDownEntry를 pendingPointerDowns[pointerId]로 둡니다.

    6. pointerDownEntry가 PerformanceEventTiming 항목인지 단언합니다.

    7. type이 pointerup 또는 contextmenu이면:

      1. window의 상호작용 횟수를 증가시킵니다.

      2. pointerMap[pointerId]를 window의 사용자 상호작용 값으로 설정합니다.

      3. pointerDownEntry의 interactionId를 pointerMap[pointerId]로 설정합니다.

    8. pointerDownEntry를 window의 대기열에 추가할 항목에 추가합니다.

    9. pendingPointerDowns[pointerId]를 제거합니다.

    10. type이 contextmenu이면 window의 컨텍스트 메뉴가 트리거되었는지를 나타내는 값을 true로 설정합니다.

    11. type이 pointercancel이면 0을 반환합니다.

    12. pointerMap[pointerId]를 반환합니다.

참고: 이 알고리즘은 이벤트에 해당하는 상호작용 ID를 할당하려고 시도합니다. 키보드 이벤트의 경우 keydown은 새로운 상호작용 ID를 생성하는 반면, keyup은 이전 keydown의 ID와 일치해야 합니다. 포인터 이벤트의 경우 pointerdown이 발생하면 pointercancel 또는 pointerup이 발생할 때까지 기다려야 해당 이벤트의 interactionId를 알 수 있습니다. 또한 click을 이전 pointerdown의 상호작용 ID와 일치시키려고 합니다. pointercancel 또는 pointerup이 발생하면 저장된 interactionId를 pointerdown에 해당하는 항목에 설정할 수 있습니다. 이 이벤트가 pointercancel이면 pointerdown에 새 상호작용 ID를 할당하지 않음을 의미합니다. 이 이벤트가 pointerup이면 새 상호작용 ID를 계산하여 pointerdown과 pointerup 모두에 설정합니다. (그리고 나중에 click이 발생하는 경우 해당 이벤트에도 설정합니다).

3.7. 이벤트 타이밍 초기화

이벤트 타이밍 초기화를 event, processingStart, interactionId로 요청받으면 다음 단계를 실행한다:
  1. event가 이벤트 타이밍 대상이 아니라면 null을 반환한다.

  2. timingEntry를 event의 관련 realm에서 새 PerformanceEventTiming 객체로 생성한다.

  3. timingEntry의 name 을 event의 type 값으로 설정한다.

  4. timingEntry의 entryType 을 "event"로 설정한다.

  5. timingEntry의 startTime 을 event의 timeStamp 값으로 설정한다.

  6. timingEntry의 processingStart 를 processingStart로 설정한다.

  7. timingEntry의 cancelable 을 event의 cancelable 값으로 설정한다.

  8. timingEntry의 interactionId 를 interactionId로 설정한다.

  9. timingEntry를 반환한다.

3.8. 이벤트 타이밍 종료

finalize event timing을 요청받았을 때, timingEntry, event, target, processingEnd을 입력값으로 다음 단계를 수행한다:
  1. timingEntry가 null이면, 반환한다.

  2. relevantGlobal을 target의 관련 전역 객체로 설정한다.

  3. relevantGlobal이 Window를 구현하지 않는다면, 반환한다.

  4. timingEntry의 processingEnd 값을 processingEnd로 설정한다.

  5. target이 Node를 구현한다고 단언한다.

    참고: 이 단언은 Event Timing API에서 지원하는 이벤트 타입 때문에 항상 성립한다.

  6. timingEntry의 연관된 eventTarget을 target으로 설정한다.

    참고: 이는 eventTarget을 마지막 이벤트 타겟으로 설정한다. 즉, 재타겟팅이 발생하는 경우, 루트에 가장 가까운 마지막 타겟이 사용된다.

  7. timingEntry의 targetSelector 값을 target을 입력값으로 하여 CSS 선택자 생성 알고리즘을 실행한 결과로 설정한다.

  8. event의 type 속성 값이 pointerdown이면:

    1. pendingPointerDowns를 relevantGlobal의 대기 중인 pointerdown들로 설정한다.

    2. pointerId를 event의 pointerId로 설정한다.

    3. pendingPointerDowns[pointerId]가 존재하면:

      1. previousPointerDownEntry를 pendingPointerDowns[pointerId]로 설정한다.

      2. previousPointerDownEntry를 relevantGlobal의 대기시킬 entries에 추가한다.

    4. pendingPointerDowns[pointerId]를 timingEntry로 설정한다.

    5. relevantGlobal의 is contextmenu triggered를 false로 설정한다.

  9. 그 외에, event의 type 속성 값이 keydown이라면:

    1. event의 isComposing 속성 값이 true이면:

      1. timingEntry를 relevantGlobal의 대기시킬 entries에 추가한다.

      2. 반환한다.

    2. pendingKeyDowns를 relevantGlobal의 대기 중인 keydown들로 설정한다.

    3. code를 event의 keyCode 값으로 설정한다.

    4. pendingKeyDowns[code]가 존재하면:

      1. previousKeyDownEntry를 pendingKeyDowns[code]로 설정한다.

      2. code가 229가 아니라면:

        1. relevantGlobal의 user interaction value 값을 UA가 선택한 작은 값만큼 증가시킨다.

        2. previousKeyDownEntry의 interactionId 값을 relevantGlobal의 user interaction value로 설정한다.

        참고: 229는 IME 키보드 이벤트에 해당하는 특수 케이스다. 때때로 사용자 에이전트가 이 이벤트를 여러 번 전송하는데, 이는 키를 반복해서 누르는 상황과는 다르다.

      3. previousKeyDownEntry를 relevantGlobal의 대기시킬 entries에 추가한다.

    5. pendingKeyDowns[code]를 timingEntry로 설정한다.

  10. 그 외의 경우:

    1. timingEntry를 relevantGlobal의 대기시킬 entries에 추가한다.

3.9. 대기 중인 이벤트 타이밍 엔트리 디스패치

대기 중인 이벤트 타이밍 엔트리 디스패치를 Document doc에 대해 요청받으면 다음 단계를 실행한다:
  1. window를 doc의 관련 글로벌 객체로 한다.

  2. renderingTimestamp를 현재 고해상도 시각으로 한다.

  3. window의 entries to be queued의 각 timingEntry에 대해:

    1. 이벤트 타이밍 엔트리 duration 설정을 timingEntry, window, renderingTimestamp로 실행한다.

    2. timingEntry의 duration 값이 16 이상이면 queue timingEntry를 실행한다.

  4. window의 대기할 entry 목록을 빈 리스트로 설정한다.

  5. window의 pending pointer downs의 값들에 대해 각 pendingPointerDownEntry마다:

    1. 이벤트 타이밍 엔트리 duration 설정을 pendingPointerDownEntry, window, renderingTimestamp로 실행한다.

  6. window의 pending key downs의 값들에 대해 각 pendingKeyDownEntry마다:

    1. 이벤트 타이밍 엔트리 duration 설정을 pendingKeyDownEntry, window, renderingTimestamp로 실행한다.

이벤트 타이밍 엔트리 duration 설정을 PerformanceEventTiming timingEntry, Window window, DOMHighResTimeStamp renderingTimestamp로 요청받으면 다음 단계를 실행한다:
  1. timingEntry의 duration 값이 0이 아니면 반환한다.

  2. start를 timingEntry의 startTime 값으로 한다.

  3. timingEntry의 duration 을 DOMHighResTimeStamp 타입의 renderingTimestamp - start 계산 결과(정밀도 8ms 이하)로 설정한다.

  4. name을 timingEntry의 name 값으로 한다.

  5. 이벤트 카운트 업데이트를 위해 다음 단계를 실행한다:

    1. eventCounts를 window의 eventCounts로 한다.

    2. eventCounts가 name을 포함함을 단언한다.

    3. Set eventCounts[name]를 eventCounts[name] + 1로 설정한다.

  6. window의 has dispatched input event가 false이고 timingEntry의 interactionId 가 0이 아니면 다음 단계를 실행한다:

    1. firstInputEntry를 timingEntry의 복사본으로 한다.

    2. firstInputEntry의 entryType 을 "first-input"로 설정한다.

    3. queue firstInputEntry를 실행한다.

    4. window의 has dispatched input event를 true로 설정한다.

3.10. 타겟 선택자

CSS 선택자 생성을 EventTarget target에 대해 실행하려면, 다음 단계를 따른다:
  1. target이 Node인 경우, 다음 단계를 실행한다:

    1. selector를 target의 nodeName의 초기값으로 하는 문자열로 설정한다.

    2. target이 Element인 경우, 다음 단계를 실행한다:

      1. target이 `id` 속성을 가지고 있으면, selector를 « selector, "#", `id` 속성 값 »을 연결한 값으로 설정한다.

      2. 그 외에 target이 `src` 속성을 가지고 있으면, selector를 « selector, "[src=", `src` 속성 값, "]" »을 연결한 값으로 설정한다.

    3. selector를 반환한다.

  2. 그 외의 경우, 빈 문자열을 반환한다.

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

고해상도 타이머는 보안상 우려가 있기 때문에 웹 플랫폼에 더 많은 고해상도 타이머를 도입하고 싶지는 않습니다. 이벤트 핸들러 타임스탬프는 performance.now()와 동일한 정밀도를 가집니다. processingStart와 processingEnd 는 이 API를 사용하지 않고도 계산할 수 있으므로, 해당 속성을 노출해도 새로운 공격면이 생기지 않습니다. 따라서 duration 만이 추가적인 고려가 필요합니다.

duration 값은 8밀리초 단위의 정밀도를 갖습니다(이렇게 반올림하여 계산됨). 따라서 이 타임스탬프로 고해상도 타이머를 만들 수는 없습니다. 하지만 이 값은 웹 개발자들이 쉽게 얻을 수 없는 새로운 정보를 제공합니다: 이벤트 처리 후 픽셀이 그려지는 시간입니다. 특히 이 정밀도를 감안할 때, 타임스탬프를 노출하는 것에 보안이나 프라이버시 문제가 있다고 생각하지 않습니다. 유용한 정보만 최소한으로 노출하고자, 우리는 8밀리초를 정밀도로 선택했습니다. 이는 120Hz 디스플레이에서도 비교적 정확한 타이밍을 제공할 수 있습니다.

duration 의 기본 컷오프 값으로 104ms를 선택한 것은 100ms보다 큰 첫 번째 8의 배수이기 때문입니다. 반올림된 duration이 104ms 이상이면, 반올림 전 duration은 100ms 이상이 됩니다. 이런 이벤트는 100ms 이내에 처리되지 않아 사용자 경험에 부정적인 영향을 줄 가능성이 높습니다.

durationThreshold 의 최소값으로 16ms를 선택한 이유는 일반적인 사용 사례에서 반응이 부드럽게 이루어짐을 보장하기 위함입니다. 120Hz 디스플레이에서는 프레임 하나를 초과하여 건너뛰면 16ms 이상이 되고, 해당 사용자 입력에 대응하는 엔트리는 최소값 기준으로 API에 노출됩니다.

적합성

문서 규칙

적합성 요구사항은 설명적 단언과 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" 등) 의 의미에 따라 해석해야 합니다.

알고리즘이나 구체적 단계로 표현된 적합성 요구사항은 최종 결과가 동등하다면 어떤 방식으로든 구현할 수 있습니다. 특히, 본 명세에 정의된 알고리즘은 이해하기 쉽게 설계된 것이며 성능을 염두에 둔 것이 아닙니다. 구현자는 최적화를 권장합니다.

색인

이 명세에서 정의된 용어

참조로 정의된 용어

참고문헌

규범적 참고문헌

[DOM]
Anne van Kesteren. DOM 표준. 현행 표준. URL: https://dom.spec.whatwg.org/
[HR-TIME-2]
Ilya Grigorik. 고해상도 시간 레벨 2. 21일 11월 2019년. REC. URL: https://www.w3.org/TR/hr-time-2/
[HTML]
Anne van Kesteren; 외. HTML 표준. 현행 표준. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra 표준. 현행 표준. URL: https://infra.spec.whatwg.org/
[PAINT-TIMING]
Ian Clelland; Noam Rosenthal. 페인트 타이밍. 2일 10월 2026년. WD. URL: https://www.w3.org/TR/paint-timing/
[PERFORMANCE-TIMELINE-2]
Nicolas Pena Moreno. 성능 타임라인. 2025년 5월 21일. CRD. URL: https://www.w3.org/TR/performance-timeline/
[POINTEREVENTS4]
Patrick Lauke; Robert Flack. 포인터 이벤트. 2026년 10월 8일. WD. URL: https://www.w3.org/TR/pointerevents4/
[RFC2119]
S. Bradner. RFC에서 요구사항 수준을 나타내는 데 사용하는 핵심 단어. 1997년 3월. 현행 모범 사례. URL: https://datatracker.ietf.org/doc/html/rfc2119
[TOUCH-EVENTS]
Doug Schepers; 외. 터치 이벤트. 10일 10월 2013년. REC. URL: https://www.w3.org/TR/touch-events/
[UIEVENTS]
Xiaoqian Wu. UI 이벤트. 2026년 2월 21일. WD. URL: https://www.w3.org/TR/uievents/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL 표준. 현행 표준. URL: https://webidl.spec.whatwg.org/

IDL 색인

[Exposed=Window]
interface PerformanceEventTiming : PerformanceEntry {
    readonly attribute DOMHighResTimeStamp processingStart;
    readonly attribute DOMHighResTimeStamp processingEnd;
    readonly attribute boolean cancelable;
    readonly attribute Node? target;
    readonly attribute DOMString targetSelector;
    readonly attribute unsigned long long interactionId;
    [Default] object toJSON();
};

[Exposed=Window]
interface EventCounts {
    readonly maplike<DOMString, unsigned long long>;
};

[Exposed=Window]
partial interface Performance {
    [SameObject] readonly attribute EventCounts eventCounts;
    readonly attribute unsigned long long interactionCount;
};

partial dictionary PerformanceObserverInit {
    DOMHighResTimeStamp durationThreshold;
};

MDN

EventCounts

Firefox89+SafariNoneChrome85+
Opera?Edge85+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

Performance/eventCounts

Firefox89+SafariNoneChrome85+
Opera?Edge85+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
Node.jsNone
MDN

PerformanceEventTiming/cancelable

Firefox89+SafariNoneChrome76+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
⚠MDN

PerformanceEventTiming/interactionId

In only one current engine.

FirefoxNoneSafariNoneChrome96+
Opera?Edge96+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

PerformanceEventTiming/processingEnd

Firefox89+SafariNoneChrome76+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

PerformanceEventTiming/processingStart

Firefox89+SafariNoneChrome76+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

PerformanceEventTiming/target

Firefox89+SafariNoneChrome85+
Opera?Edge85+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

PerformanceEventTiming/toJSON

Firefox89+SafariNoneChrome76+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

PerformanceEventTiming

Firefox89+SafariNoneChrome76+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?