성능 타임라인

W3C 후보 권고안 초안

이 문서에 대한 추가 정보
이 버전:
https://www.w3.org/TR/2025/CRD-performance-timeline-20250521/
최신 공개 버전:
https://www.w3.org/TR/performance-timeline/
최신 편집자 초안:
https://w3c.github.io/performance-timeline/
히스토리:
https://www.w3.org/standards/history/performance-timeline
커밋 히스토리
테스트 슈트:
https://github.com/web-platform-tests/wpt/tree/master/performance-timeline
구현 보고서:
https://wpt.fyi/results/performance-timeline
에디터:
Nicolás Peña Moreno (Google)
이전 에디터:
Ilya Grigorik (Google)
(Microsoft Corp.) (2014년 11월까지)
Zhiheng Wang (Google) (2013년 7월까지)
피드백:
GitHub w3c/performance-timeline (풀 리퀘스트, 새 이슈, 오픈 이슈)

요약

이 명세는 고해상도 시간 명세 [HR-TIME-3]를 확장하여 고해상도 성능 메트릭 데이터를 저장하고 조회하는 메서드를 제공합니다.

이 문서의 상태

이 섹션은 이 문서가 출판될 당시의 상태를 설명합니다. 현재 W3C 출판물 목록과 이 기술 보고서의 최신 개정본은 W3C 표준 및 초안 인덱스에서 확인할 수 있습니다: https://www.w3.org/TR/.

이 Performance Timeline 명세는 첫 번째 버전의 [PERFORMANCE-TIMELINE]을 대체하며 다음 내용을 포함합니다:

이 문서는 Web Performance Working Group권고안 트랙을 사용하여 후보 권고안 초안으로 발행한 것입니다.

후보 권고안으로서의 출판은 W3C 및 그 회원들의 승인/지지를 의미하지 않습니다. 후보 권고안 초안은 이전 후보 권고안에서 작업 그룹이 이후 후보 권고안 스냅샷에 포함하려는 변경 사항을 통합합니다.

이 문서는 초안이며 언제든지 업데이트, 교체 또는 폐기될 수 있습니다. 진행 중인 작업 외의 인용은 적절하지 않습니다.

이 문서는 W3C 특허 정책에 따라 운영되는 그룹이 제작했습니다. W3C공개 특허 공개 목록 을 관리하며, 해당 그룹의 산출물과 관련하여 제출된 특허 공개 내역과 특허 공개 방법에 대한 안내도 포함되어 있습니다. 특정 특허에 대해 실제로 알고 있고, 그 특허가 필수 청구항 을 포함한다고 생각되는 경우, W3C 특허 정책 제6절에 따라 정보를 공개해야 합니다.

이 문서는 2023년 11월 3일 W3C 프로세스 문서에 의해 관리됩니다.

1. 소개

이 섹션은 비규범적입니다.

웹 애플리케이션의 성능 특성을 정확하게 측정하는 것은 웹 애플리케이션을 더욱 빠르게 만드는 데 중요한 요소입니다. 이 명세는 웹 개발자가 웹 애플리케이션의 전체 라이프사이클에서 다양한 성능 지표에 접근하고, 계측하며, 조회할 수 있도록 하는 Performance Timeline 기본 요소를 정의합니다.

[NAVIGATION-TIMING-2], [RESOURCE-TIMING-2], [USER-TIMING-2] 는 각각 문서의 내비게이션, 페이지의 리소스, 개발자 스크립트와 관련된 타이밍 정보를 정의하는 명세의 예시입니다. 이들 및 기타 성능 인터페이스는 웹 애플리케이션의 Performance Timeline을 설명하는 성능 지표를 정의합니다. 예를 들어, 다음 스크립트는 개발자가 문서의 내비게이션, 페이지의 리소스, 개발자 스크립트와 관련된 성능 지표를 얻기 위해 Performance Timeline에 접근하는 방법을 보여줍니다:

<!doctype html>
<html>
<head></head>
<body onload="init()">
  <img id="image0" src="https://www.w3.org/Icons/w3c_main.png" />
  <script>
    function init() {
      // see [[USER-TIMING-2]]
      performance.mark("startWork");
      doWork(); // 개발자 코드
      performance.mark("endWork");
      measurePerf();
    }
    function measurePerf() {
      performance
        .getEntries()
        .map(entry => JSON.stringify(entry, null, 2))
        .forEach(json => console.log(json));
    }
  </script>
  </body>
</html>

또한 개발자는 Performance Timeline을 관찰하여 새로운 성능 지표 또는 선택적으로 지정된 타입의 이전에 버퍼링된 성능 지표에 대한 알림을 PerformanceObserver 인터페이스를 통해 받을 수 있습니다.

PerformanceObserver 인터페이스가 추가되었으며, 첫 번째 예제에 나온 버퍼 기반 접근 방식의 한계를 해결하기 위해 설계되었습니다. PerformanceObserver 인터페이스를 사용하면 애플리케이션은 다음과 같은 이점을 얻습니다:

개발자는 가능한 경우 PerformanceObserver를 사용할 것을 권장합니다. 또한 새로운 성능 API 및 지표는 PerformanceObserver 인터페이스를 통해서만 제공될 수 있습니다. 옵저버는 생성자에서 콜백을 지정하고, observe() 메서드를 통해 관심 있는 성능 엔트리를 지정하여 동작합니다. 사용자 에이전트는 콜백을 실행할 시점을 선택하며, 콜백은 큐에 추가된 성능 엔트리를 받게 됩니다.

PerformanceObserver 인터페이스를 사용할 때 초기 페이지 로드와 관련된 특별한 고려사항이 있습니다: 등록이 활성화되어야 이벤트를 받을 수 있지만, 등록 스크립트가 사용 가능하지 않거나 크리티컬 패스에 포함되지 않을 수도 있습니다. 이를 해결하기 위해 사용자 에이전트는 페이지가 구성되는 동안 일부 이벤트를 버퍼링하며, 이러한 버퍼링된 이벤트는 옵저버를 등록할 때 buffered 플래그를 통해 접근할 수 있습니다. 플래그가 설정되면 사용자 에이전트는 지정된 엔트리 타입에 대해 버퍼링된 이벤트를 조회 및 디스패치하고, observe() 호출 이후 첫 번째 콜백에서 전달합니다.

참고

버퍼링되는 이벤트의 개수는 해당 지표를 정의하는 명세에 의해 결정되며, 버퍼링은 최초 N개의 이벤트만을 위한 것이며, 무제한 또는 지속적인 버퍼링이 아닙니다.

<!doctype html>
<html>
<head></head>
<body>
<img id="image0" src="https://www.w3.org/Icons/w3c_main.png" />
<script>
// 사용하려는 엔트리 타입이 지원되지 않을 때를 감지합니다.
function detectSupport(entryTypes) {
  for (const entryType of entryTypes) {
    if (!PerformanceObserver.supportedEntryTypes.includes(entryType)) {
      // 클라이언트 측 분석에 |entryType|이 지원되지 않음을 알립니다.
    }
  }
}
detectSupport(["resource", "mark", "measure"]);
const userTimingObserver = new PerformanceObserver(list => {
  list
    .getEntries()
    // 관심 있는 값을 가져옵니다
    .map(({ name, entryType, startTime, duration }) => {
      const obj = {
        "Duration": duration,
        "Entry Type": entryType,
        "Name": name,
        "Start Time": startTime,
      };
      return JSON.stringify(obj, null, 2);
    })
    // 콘솔에 표시합니다.
    .forEach(console.log);
  // 이벤트 처리 후 연결 해제합니다.
  userTimingObserver.disconnect();
});
// User-Timing에 대해 새로운 이벤트를 구독합니다.
userTimingObserver.observe({entryTypes: ["mark", "measure"]});
const resourceObserver = new PerformanceObserver(list => {
  list
    .getEntries()
    // 관심 있는 값을 가져옵니다
    .map(({ name, startTime, fetchStart, responseStart, responseEnd }) => {
      const obj = {
        "Name": name,
        "Start Time": startTime,
        "Fetch Start": fetchStart,
        "Response Start": responseStart,
        "Response End": responseEnd,
      };
      return JSON.stringify(obj, null, 2);
    })
    // 콘솔에 표시합니다.
    .forEach(console.log);
  // 이벤트 처리 후 연결 해제합니다.
  resourceObserver.disconnect();
});
// Resource Timing에 대해 버퍼링된 이벤트를 조회하고 새로운 이벤트를 구독합니다.
resourceObserver.observe({type: "resource", buffered: true});
</script>
</body>
</html>

2. 적합성

비규범적으로 표시된 섹션과 저작 가이드라인, 도해, 예제, 참고 사항은 모두 비규범적입니다. 이 명세의 그 외 모든 내용은 규범적입니다.

이 문서의 MUST, MUST NOT, SHOULD 키워드는 BCP 14 [RFC2119] [RFC8174] 에서 설명한 대로, 반드시 대문자로 표시될 때만 이 의미대로 해석해야 합니다.

알고리즘이나 특정 단계로 기술된 적합성 요구 사항은 결과가 동일하다면 어떤 방식으로든 구현할 수 있습니다. (특히 이 명세에 정의된 알고리즘은 따라하기 쉽도록 설계된 것이며, 성능을 위한 것이 아닙니다).

3. 성능 타임라인

글로벌 오브젝트는 다음을 가진다:

Document는 다음을 가진다:

관련 성능 엔트리 튜플을 얻으려면, entryTypeglobalObject를 입력값으로 하여 다음 단계를 수행한다:

  1. map성능 엔트리 버퍼 맵 (globalObject에 연관된 것)을 가리키도록 한다.
  2. 엔트리의 값 얻기 map에서 entryType로 하여 수행하고 그 결과를 반환한다.

3.1 Performance 인터페이스 확장

이 내용은 [HR-TIME-3]의 Performance 인터페이스를 확장하며, 성능 타임라인에서 성능 메트릭 데이터를 조회할 때 사용하는 성능 관련 속성과 메서드를 포함한다.

WebIDLpartial interface Performance {
  PerformanceEntryList getEntries ();
  PerformanceEntryList getEntriesByType (DOMString type);
  PerformanceEntryList getEntriesByName (DOMString name, optional DOMString type);
};
typedef sequence<PerformanceEntry> PerformanceEntryList;

PerformanceEntryListPerformanceEntry 시퀀스를 나타내며, 개발자에게 자바스크립트 배열에서 제공되는 모든 편의 메서드를 제공한다.

3.1.1 getEntries() 메서드

이름과 타입으로 버퍼 맵 필터링 알고리즘에서 nametypenull로 설정해 반환된 PerformanceEntryList 객체를 반환한다.

3.1.2 getEntriesByType() 메서드

이름과 타입으로 버퍼 맵 필터링 알고리즘에서 namenull, type을 메서드의 입력 type 파라미터로 설정해 반환된 PerformanceEntryList 객체를 반환한다.

3.1.3 getEntriesByName() 메서드

이름과 타입으로 버퍼 맵 필터링 알고리즘에서 name을 메서드 입력 name 파라미터로, type을 선택적 entryType이 생략된 경우 null, 그렇지 않으면 메서드의 입력 type 파라미터로 설정해 반환된 PerformanceEntryList 객체를 반환한다.

4. PerformanceEntry 인터페이스

PerformanceEntry 인터페이스는 다양한 성능 메트릭의 성능 데이터를 담는다.

WebIDL[Exposed=(Window,Worker)]
interface PerformanceEntry {
  readonly    attribute unsigned long long  id;
  readonly    attribute DOMString           name;
  readonly    attribute DOMString           entryType;
  readonly    attribute DOMHighResTimeStamp startTime;
  readonly    attribute DOMHighResTimeStamp duration;
  readonly    attribute unsigned long long  navigationId;
  [Default] object toJSON();
};
name
이 속성은 초기화된 값을 반환해야 하며, 이 PerformanceEntry 객체의 식별자를 나타낸다. 이 식별자는 반드시 유일할 필요는 없다.
entryType
이 속성은 초기화된 값을 반환해야 한다.
참고

모든 entryType 값은 관련 레지스트리에 정의되어 있다. 예시: "mark", "measure" [USER-TIMING-2], "navigation" [NAVIGATION-TIMING-2], 그리고 "resource" [RESOURCE-TIMING-2].

startTime
이 속성은 초기화된 값을 반환해야 하며, 이 성능 메트릭의 최초 기록된 타임스탬프의 시간 값을 나타낸다.
duration
duration 속성의 getter 단계는 this종료 시간이 0이면 0을 반환하고, 그렇지 않으면 this종료 시간 - thisstartTime 값을 반환한다.
navigationId
이 속성은 반드시 초기화된 값을 반환해야 한다.

toJSON이 호출되면, [WebIDL]의 기본 toJSON 단계를 실행한다.

PerformanceEntryDOMHighResTimeStamp 종료 시간을 가지며, 초기값은 0이다.

PerformanceEntry를 초기화한다 entry에 대해 DOMHighResTimeStamp startTime, DOMString entryType, DOMString name, 그리고 선택적으로 DOMHighResTimeStamp endTime (기본값 0)이 주어졌을 때:

  1. entryType엔트리 타입 레지스트리에 정의되어 있는지 확인한다.
  2. entrystartTimestartTime으로 초기화한다.
  3. entryentryTypeentryType으로 초기화한다.
  4. entrynamename으로 초기화한다.
  5. entry종료 시간endTime으로 초기화한다.

5. PerformanceObserver 인터페이스

PerformanceObserver 인터페이스는 성능 타임라인을 관찰하여 새로운 성능 메트릭이 기록될 때와 선택적으로 버퍼링된 성능 메트릭에 대한 알림을 받을 수 있다.

PerformanceObserver는 다음과 같은 연관 개념을 가진다:

PerformanceObserver(callback) 생성자는 옵저버 콜백callback으로 설정하여 새로운 PerformanceObserver 객체를 생성하고 반환해야 한다.

등록된 성능 옵저버구조체이며, 옵저버 멤버( PerformanceObserver 객체)와 옵션 리스트 멤버( PerformanceObserverInit 딕셔너리 리스트)로 구성된다.

WebIDLcallback PerformanceObserverCallback = undefined (PerformanceObserverEntryList entries,
                                             PerformanceObserver observer,
                                             optional PerformanceObserverCallbackOptions options = {});
[Exposed=(Window,Worker)]
interface PerformanceObserver {
  constructor(PerformanceObserverCallback callback);
  undefined observe (optional PerformanceObserverInit options = {});
  undefined disconnect ();
  PerformanceEntryList takeRecords();
  [SameObject] static readonly attribute FrozenArray<DOMString> supportedEntryTypes;
};
참고

성능 오버헤드를 최소화하려면 애플리케이션은 관심 있는 이벤트 타입만 구독하고, 더 이상 성능 데이터를 관찰할 필요가 없을 때 옵저버를 해제해야 한다. 이름으로 필터링하는 기능은 모든 이벤트 타입을 암묵적으로 구독해야 하므로 지원하지 않으며, 이는 많은 이벤트가 생성될 수 있으므로 권장되지 않는다.

5.1 PerformanceObserverCallbackOptions 딕셔너리

WebIDLdictionary PerformanceObserverCallbackOptions {
  unsigned long long droppedEntriesCount;
};
droppedEntriesCount
옵저버가 관찰 중인 엔트리 타입에서 드롭된 엔트리의 개수를 나타내는 정수. PerformanceObserver드롭된 엔트리 필요 여부가 설정된 경우에 해당한다.

5.2 observe() 메서드

observe() 메서드는 사용자 에이전트에게 옵저버를 등록하도록 지시하며, 다음 단계를 실행해야 한다:

  1. relevantGlobalthis관련 글로벌 오브젝트로 한다.
  2. optionsentryTypestype 멤버가 모두 생략된 경우, "TypeError"를 throw한다.
  3. optionsentryTypes가 존재하고, 다른 멤버도 존재하면 "TypeError"를 throw한다.
  4. this옵저버 타입을 다음 단계로 업데이트 또는 확인한다:
    1. this옵저버 타입"undefined"인 경우:
      1. optionsentryTypes가 존재하면, this옵저버 타입"multiple"로 설정한다.
      2. optionstype가 존재하면, this옵저버 타입"single"로 설정한다.
    2. this옵저버 타입"single"이고 optionsentryTypes가 존재하면, "InvalidModificationError"를 throw한다.
    3. this옵저버 타입"multiple"이고 optionstype가 존재하면, "InvalidModificationError"를 throw한다.
  5. this드롭된 엔트리 필요 여부를 true로 설정한다.
  6. this옵저버 타입"multiple"이면, 다음 단계를 실행한다:
    1. entry typesoptionsentryTypes 시퀀스로 한다.
    2. entry types에서 relevantGlobal지원되는 엔트리 타입 동결 배열에 포함되지 않은 모든 타입을 제거한다. 사용자 에이전트는 SHOULD 개발자에게 entry types가 수정되었음을 알려야 한다. 예를 들어, 콘솔 경고로 제거된 타입을 알려줄 수 있다.
    3. 결과 entry types 시퀀스가 빈 시퀀스라면, 이 단계들을 중단한다. 사용자 에이전트는 SHOULD 이 단계가 중단되었음을 개발자에게 알려야 한다. 예를 들어, 콘솔 경고가 적절하다.
    4. relevantGlobal등록된 성능 옵저버 객체 리스트등록된 성능 옵저버옵저버this인 것이 있으면, 그 옵션 리스트options 하나만 담은 리스트로 바꾼다.
    5. 그렇지 않으면, 등록된 성능 옵저버 객체를 생성해서 relevantGlobal등록된 성능 옵저버 객체 리스트에 추가하는데, 옵저버에는 this를, 옵션 리스트에는 options 하나만 담은 리스트를 설정한다.
  7. 그렇지 않으면, 다음 단계를 실행한다:
    1. this옵저버 타입"single"임을 단언한다.
    2. optionstyperelevantGlobal지원되는 엔트리 타입 동결 배열에 포함되지 않으면, 이 단계들을 중단한다. 사용자 에이전트는 SHOULD 이 상황을 개발자에게 알려야 한다. 예를 들어, 콘솔 경고가 적절하다.
    3. relevantGlobal등록된 성능 옵저버 객체 리스트등록된 성능 옵저버 obs옵저버this인 경우:
      1. obs옵션 리스트PerformanceObserverInit 아이템 currentOptions가 있고, 그 typeoptionstype과 같으면, currentOptionsoptions로 교체한다.
      2. 그렇지 않으면, optionsobs옵션 리스트에 추가한다.
    4. 그렇지 않으면, 등록된 성능 옵저버 객체를 생성해서 relevantGlobal등록된 성능 옵저버 객체 리스트에 추가하는데, 옵저버에는 this를, 옵션 리스트에는 options 하나만 담은 리스트를 설정한다.
    5. optionsbuffered 플래그가 설정된 경우:
      1. tupleoptionstyperelevantGlobal관련 성능 엔트리 튜플로 한다.
      2. tuple성능 엔트리 버퍼의 각 entry에 대해:

        1. should add entryentryoptions를 인자로 넘겨 true를 반환하면, entry옵저버 버퍼에 append한다.
      3. PerformanceObserver 작업 큐에 추가relevantGlobal을 인자로 하여 실행한다.
참고

PerformanceObserver 객체는 항상 observe()optionsentryTypes가 설정된 상태로 호출하거나, optionstype이 설정된 상태로 호출해야 한다. 만약 하나의 PerformanceObserverobserve()entryTypes와 함께 호출하고, 다시 type과 함께 호출하면, 예외가 발생한다. 이는 호출이 어떻게 중첩되는지 혼란을 방지하기 위한 것이다. entryTypes를 사용할 때는 PerformanceObserverInit의 다른 파라미터를 사용할 수 없다. 또한, 여러 번 observe()를 호출하면 이전 값을 덮어쓰며, 한 번의 호출이면 충분하다. 반면 type을 사용할 때는 호출이 쌓인다. 같은 type으로 여러 번 호출하면 덮어쓴다.

5.2.1 PerformanceObserverInit 딕셔너리

WebIDLdictionary PerformanceObserverInit {
  sequence<DOMString> entryTypes;
  DOMString type;
  boolean buffered;
};
entryTypes
관찰할 엔트리 타입 목록. 존재하는 경우, 목록은 MUST NOT 비어 있으면 안 되고, 다른 멤버는 MUST NOT 존재하면 안 된다. 사용자 에이전트가 인식하지 못하는 타입은 MUST 무시되어야 한다.
type
관찰할 단일 엔트리 타입. 사용자 에이전트가 인식하지 못하는 타입은 MUST 무시되어야 한다. 다른 멤버가 존재할 수 있다.
buffered
버퍼링된 엔트리를 옵저버의 버퍼에 추가할지 여부를 나타내는 플래그.

5.2.2 PerformanceObserverEntryList 인터페이스

WebIDL[Exposed=(Window,Worker)]
interface PerformanceObserverEntryList {
  PerformanceEntryList getEntries();
  PerformanceEntryList getEntriesByType (DOMString type);
  PerformanceEntryList getEntriesByName (DOMString name, optional DOMString type);
};

PerformanceObserverEntryList 객체는 엔트리 리스트를 가지며, PerformanceEntryList로 구성되고, 생성 시 초기화된다.

5.2.2.1 getEntries() 메서드

이름과 타입으로 버퍼 필터링 알고리즘에서 this엔트리 리스트, nametypenull로 설정해 반환된 PerformanceEntryList 객체를 반환한다.

5.2.2.2 getEntriesByType() 메서드

이름과 타입으로 버퍼 필터링 알고리즘에서 this엔트리 리스트, namenull, type을 메서드의 입력 type 파라미터로 설정해 반환된 PerformanceEntryList 객체를 반환한다.

5.2.2.3 getEntriesByName() 메서드

이름과 타입으로 버퍼 필터링 알고리즘에서 this엔트리 리스트, name을 메서드 입력 name 파라미터로, type을 선택적 entryType이 생략된 경우 null, 그렇지 않으면 메서드의 입력 type 파라미터로 설정해 반환된 PerformanceEntryList 객체를 반환한다.

5.3 takeRecords() 메서드

takeRecords() 메서드는 this옵저버 버퍼의 복사본을 반환하며, this옵저버 버퍼도 비워야 한다.

5.4 disconnect() 메서드

disconnect() 메서드는 다음을 수행해야 한다:

  1. this등록된 성능 옵저버 객체 리스트에서 제거한다 (관련 글로벌 오브젝트 기준).
  2. this옵저버 버퍼를 비운다.
  3. this옵션 리스트를 비운다.

5.5 supportedEntryTypes 속성

글로벌 오브젝트는 연관된 지원되는 엔트리 타입의 동결 배열을 가지며, 이는 레지스트리에서 해당 글로벌 오브젝트가 지원하는 문자열의 시퀀스를 알파벳순으로 정렬한 뒤 FrozenArray 생성으로 초기화한다.

supportedEntryTypes 속성의 getter가 호출되면 다음 단계를 실행한다:

  1. globalObject환경 설정 오브젝트의 글로벌 오브젝트로 한다.
  2. globalObject지원되는 엔트리 타입의 동결 배열을 반환한다.
참고

이 속성은 웹 개발자가 사용자 에이전트가 지원하는 엔트리 타입을 쉽게 알 수 있도록 해준다.

6. 처리

6.1 PerformanceEntry 큐에 추가

PerformanceEntry 큐에 추가(newEntry)하려면 다음 단계를 실행한다:

  1. newEntryid가 설정되지 않은 경우:
    1. idid 생성 결과값으로 한다.
    2. newEntryidid를 설정한다.
  2. interested observers를 초기에는 빈 PerformanceObserver 객체 집합으로 한다.
  3. entryTypenewEntryentryType 값으로 한다.
  4. relevantGlobalnewEntry관련 글로벌 오브젝트로 한다.
  5. relevantGlobal연관된 document를 가지는 경우:
    1. newEntrynavigationIdrelevantGlobal연관된 document가장 최근 내비게이션id 값으로 설정한다.
  6. 그렇지 않으면 newEntrynavigationId를 null로 설정한다.
  7. relevantGlobal등록된 성능 옵저버 객체 리스트의 각 등록된 성능 옵저버 regObs에 대해:
    1. regObs옵션 리스트PerformanceObserverInit options가 있고, 그 entryTypesentryType을 포함하거나, typeentryType과 같다면:

      1. should add entrynewEntryoptions를 넘겨 true면, regObs옵저버interested observers에 추가한다.
  8. interested observers의 각 observer에 대해:
    1. newEntryobserver옵저버 버퍼에 추가한다.
  9. tupleentryTyperelevantGlobal관련 성능 엔트리 튜플로 한다.
  10. isBufferFull성능 엔트리 버퍼가 가득 찼는지 확인 알고리즘 결과값으로 한다.
  11. shouldAddshould add entrynewEntry를 넘긴 결과값으로 한다.
  12. isBufferFull이 false이고 shouldAdd이 true이면, tuple성능 엔트리 버퍼newEntry를 추가한다.
  13. PerformanceObserver 작업 큐에 추가relevantGlobal을 인자로 실행한다.

6.2 내비게이션 PerformanceEntry 큐에 추가

내비게이션 PerformanceEntry 큐에 추가(newEntry)하려면 다음 단계를 실행한다:

  1. idid 생성 결과값으로 한다.
  2. relevantGlobalnewEntry관련 글로벌 오브젝트로 한다.
  3. newEntryidid로 설정한다.
  4. newEntrynavigationIdid로 설정한다.
  5. relevantGlobal연관된 document를 가지는 경우:
    1. relevantGlobal연관된 document가장 최근 내비게이션newEntry로 설정한다.
  6. PerformanceEntry 큐에 추가newEntry를 인자로 실행한다.

6.3 PerformanceObserver 작업 큐에 추가

PerformanceObserver 작업 큐에 추가를 요청받으면, relevantGlobal을 인자로 다음 단계를 실행한다:

  1. relevantGlobal성능 옵저버 작업 큐 플래그가 설정되어 있으면, 이 단계들을 종료한다.
  2. relevantGlobal성능 옵저버 작업 큐 플래그를 설정한다.
  3. 작업 큐에 추가를 실행하는데, 다음 하위 단계를 포함한다. 큐에 추가된 작업의 작업 소스성능 타임라인 작업 소스이다.
    1. relevantGlobal성능 옵저버 작업 큐 플래그를 해제한다.
    2. notifyListrelevantGlobal등록된 성능 옵저버 객체 리스트의 복사본으로 한다.
    3. notifyList의 각 등록된 성능 옵저버 객체 registeredObserver에 대해 다음 단계 실행:
      1. poregisteredObserver옵저버로 한다.
      2. entriespo옵저버 버퍼의 복사본으로 한다.
      3. entries가 비어 있으면 return.
      4. po옵저버 버퍼를 비운다.
      5. observerEntryList를 새로운 PerformanceObserverEntryList로 생성하며, 엔트리 리스트entries로 설정한다.
      6. droppedEntriesCount를 null로 한다.
      7. po드롭된 엔트리 필요 여부가 설정되어 있으면 다음 단계 실행:
        1. droppedEntriesCount를 0으로 설정한다.
        2. registeredObserver옵션 리스트의 각 PerformanceObserverInit item에 대해:
          1. itemtype 또는 entryTypes에 나타나는 각 DOMString entryType에 대해:
            1. maprelevantGlobal성능 엔트리 버퍼 맵로 한다.
            2. tuplemap에서 entryType로 하여 얻은 값으로 한다.
            3. droppedEntriesCounttuple드롭된 엔트리 카운트를 더한다.
        3. po드롭된 엔트리 필요 여부를 false로 설정한다.
      8. callbackOptionsPerformanceObserverCallbackOptions로 생성하며, droppedEntriesCountdroppedEntriesCount가 null이 아니면 해당 값으로 하고, 아니면 설정하지 않는다.
      9. 콜백 함수 호출을 실행하는데, po옵저버 콜백에 « observerEntryList, po, callbackOptions », "report", po를 전달한다.

성능 타임라인 작업 큐는 낮은 우선순위 큐로, 성능 모니터링 코드의 영향을 최소화하기 위해 사용자 에이전트가 가능하다면 유휴 시간에 처리해야 한다.

6.4 이름과 타입으로 버퍼 맵 필터링

선택적 nametype으로 이름과 타입으로 버퍼 맵 필터링 알고리즘을 실행하면 다음 단계를 따른다:

  1. result를 초기에는 빈 리스트로 한다.
  2. map성능 엔트리 버퍼 맵으로 하고, 이는 관련 글로벌 오브젝트에 연결되어 있다(this 기준).
  3. tuple list를 빈 리스트로 한다.
  4. type이 null이 아니면, map에서 type로 하여 얻은 값을 tuple list에 추가한다. 그렇지 않으면 map의 값을 get the valuestuple list에 할당한다.
  5. tuple list의 각 tuple에 대해 다음 단계 실행:
    1. buffertuple성능 엔트리 버퍼로 한다.
    2. tupleavailableFromTimeline이 false면, 다음 tuple로 이동한다.
    3. entries이름과 타입으로 버퍼 필터링 알고리즘을 buffer, name, type으로 실행한 결과로 한다.
    4. entries의 각 entryresult에 추가한다.
  6. results의 엔트리들을 startTime 기준으로 시간순으로 정렬한다.
  7. result를 반환한다.

6.5 이름과 타입으로 버퍼 필터링

이름과 타입으로 버퍼 필터링 알고리즘을 buffer, name, type을 인자로 실행하면 다음 단계를 따른다:

  1. result를 초기에는 빈 리스트로 한다.
  2. buffer의 각 PerformanceEntry entry에 대해 다음 단계 실행:
    1. type이 null이 아니고, typeentryentryType 속성과 동일하지 않으면 다음 entry로 이동한다.
    2. name이 null이 아니고, nameentryname 속성과 동일하지 않으면 다음 entry로 이동한다.
    3. entryresult에 추가한다.
  3. results의 엔트리들을 startTime 기준으로 시간순으로 정렬한다.
  4. result를 반환한다.

6.6 성능 엔트리 버퍼가 가득 찼는지 확인

성능 엔트리 버퍼가 가득 찼는지 확인 알고리즘을 tuple을 인자로 실행하면 다음 단계를 따른다:

  1. num current entriestuple성능 엔트리 버퍼의 크기로 설정한다.
  2. num current entriestuplesmaxBufferSize보다 작으면 false를 반환한다.
  3. tuple드롭된 엔트리 카운트를 1 증가시킨다.
  4. true를 반환한다.

6.7 Performance Entry id 생성

id 생성PerformanceEntry entry에 요청받으면 다음 단계를 실행한다:

  1. relevantGlobalentry관련 글로벌 오브젝트로 한다.
  2. relevantGlobal마지막 성능 엔트리 ID를 사용자 에이전트가 선택한 작은 숫자만큼 증가시킨다.
  3. relevantGlobal마지막 성능 엔트리 ID를 반환한다.

사용자 에이전트는 마지막 성능 엔트리 ID를 매번 작은 랜덤 정수만큼 증가시킬 수 있다. 모든 글로벌 오브젝트의 마지막 성능 엔트리 ID를 하나의 글로벌 랜덤 정수로 증가시키면 교차 출처 정보 노출이 발생할 수 있으므로 반드시 피해야 한다.

참고

마지막 성능 엔트리 ID는 초기값이 랜덤이며, 사용자 에이전트가 선택한 작은 숫자만큼 증가한다. 이는 개발자가 해당 값을 웹 애플리케이션에서 생성된 엔트리 개수 카운터로 간주하는 것을 방지하기 위함이다.

7. 프라이버시 고려사항

이 명세는 [HR-TIME-3]에서 정의된 Performance 인터페이스를 확장하며, 성능 타임라인에서 엔트리를 큐잉 및 조회하는 메서드를 제공합니다. 고해상도 타이밍 정보를 노출할 때의 프라이버시 고려사항은 [HR-TIME-3]를 참고하세요. 새로운 성능 엔트리를 도입하는 각 명세는 자체 프라이버시 고려사항을 별도로 가져야 합니다.

마지막 성능 엔트리 ID는 의도적으로 랜덤 값으로 초기화되며, 새로운 PerformanceEntry가 큐에 추가될 때마다 또 다른 작은 값만큼 증가합니다. 사용자 에이전트는 모든 사용자에게 일관된 증가값을 사용할 수도 있고, 각 글로벌 오브젝트마다 다른 증가값을 선택하거나, 각 PerformanceEntry마다 새로운 랜덤 증가값을 선택할 수도 있습니다. 그러나 교차 출처 정보 유출과 지문 채취(fingerprinting)를 방지하기 위해, 사용자 에이전트는 고유한 랜덤 정수를 선택해 모든 PerformanceEntry 객체에 일관된 증가값으로 사용해서는 안 됩니다. 이는 모든 글로벌 오브젝트에 해당됩니다.

8. 보안 고려사항

이 명세는 [HR-TIME-3]에서 정의된 Performance 인터페이스를 확장하며, 성능 타임라인에서 엔트리를 큐잉 및 조회하는 메서드를 제공합니다. 고해상도 타이밍 정보를 노출할 때의 보안 고려사항은 [HR-TIME-3]를 참고하세요. 새로운 성능 엔트리를 도입하는 각 명세는 자체 보안 고려사항을 별도로 가져야 합니다.

9. 의존성

[INFRA] 명세는 다음을 정의합니다: , 엔트리의 값 얻기.

A. IDL 인덱스

WebIDLpartial interface Performance {
  PerformanceEntryList getEntries ();
  PerformanceEntryList getEntriesByType (DOMString type);
  PerformanceEntryList getEntriesByName (DOMString name, optional DOMString type);
};
typedef sequence<PerformanceEntry> PerformanceEntryList;

[Exposed=(Window,Worker)]
interface PerformanceEntry {
  readonly    attribute unsigned long long  id;
  readonly    attribute DOMString           name;
  readonly    attribute DOMString           entryType;
  readonly    attribute DOMHighResTimeStamp startTime;
  readonly    attribute DOMHighResTimeStamp duration;
  readonly    attribute unsigned long long  navigationId;
  [Default] object toJSON();
};

callback PerformanceObserverCallback = undefined (PerformanceObserverEntryList entries,
                                             PerformanceObserver observer,
                                             optional PerformanceObserverCallbackOptions options = {});
[Exposed=(Window,Worker)]
interface PerformanceObserver {
  constructor(PerformanceObserverCallback callback);
  undefined observe (optional PerformanceObserverInit options = {});
  undefined disconnect ();
  PerformanceEntryList takeRecords();
  [SameObject] static readonly attribute FrozenArray<DOMString> supportedEntryTypes;
};

dictionary PerformanceObserverCallbackOptions {
  unsigned long long droppedEntriesCount;
};

dictionary PerformanceObserverInit {
  sequence<DOMString> entryTypes;
  DOMString type;
  boolean buffered;
};

[Exposed=(Window,Worker)]
interface PerformanceObserverEntryList {
  PerformanceEntryList getEntries();
  PerformanceEntryList getEntriesByType (DOMString type);
  PerformanceEntryList getEntriesByName (DOMString name, optional DOMString type);
};

B. 감사의 글

이 작업에 기여해주신 Arvind Jain, Boris Zbarsky, Jatinder Mann, Nat Duca, Philippe Le Hegaret, Ryosuke Niwa, Shubhie Panicker, Todd Reifsteck, Yoav Weiss, Zhiheng Wang께 감사드립니다.

C. 참고문헌

C.1 규범적 참고문헌

[dom]
DOM 표준. Anne van Kesteren. WHATWG. 현행 표준. URL: https://dom.spec.whatwg.org/
[HR-TIME-3]
고해상도 시간. Yoav Weiss. W3C. 2024년 11월 7일. W3C 작업 초안. URL: https://www.w3.org/TR/hr-time-3/
[HTML]
HTML 표준. Anne van Kesteren; Domenic Denicola; Dominic Farolino; Ian Hickson; Philip Jägenstedt; Simon Pieters. WHATWG. 현행 표준. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Infra 표준. Anne van Kesteren; Domenic Denicola. WHATWG. 현행 표준. URL: https://infra.spec.whatwg.org/
[RFC2119]
RFC에서 요구 수준을 나타내는 키워드. S. Bradner. IETF. 1997년 3월. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc2119
[RFC8174]
RFC 2119 키워드의 대소문자 모호성. B. Leiba. IETF. 2017년 5월. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc8174
[WebIDL]
Web IDL 표준. Edgar Chen; Timothy Gu. WHATWG. 현행 표준. URL: https://webidl.spec.whatwg.org/

C.2 참고용 참고문헌

[NAVIGATION-TIMING-2]
Navigation Timing Level 2. Yoav Weiss; Noam Rosenthal. W3C. 2025년 2월 13일. W3C 작업 초안. URL: https://www.w3.org/TR/navigation-timing-2/
[PERFORMANCE-TIMELINE]
Performance Timeline. Nicolas Pena Moreno. W3C. 2025년 2월 13일. CRD. URL: https://www.w3.org/TR/performance-timeline/
[RESOURCE-TIMING-2]
Resource Timing. Yoav Weiss; Noam Rosenthal. W3C. 2025년 2월 13일. CRD. URL: https://www.w3.org/TR/resource-timing/
[USER-TIMING-2]
User Timing Level 2. Ilya Grigorik. W3C. 2019년 2월 26일. W3C 권고안. URL: https://www.w3.org/TR/user-timing-2/
[WORKERS]
Web Workers. Ian Hickson. W3C. 2021년 1월 28일. W3C 작업 그룹 노트. URL: https://www.w3.org/TR/workers/