1. 소개
이 절은 비규범적입니다.
중요한 요소가 화면에 표시되는 시점을 아는 것은 페이지 로드 성능을 이해하는 데 핵심적입니다. 필수 구성요소의 빠른 렌더링만으로 만족스러운 로딩 경험이 충분히 보장되는 것은 아니지만, 이는 필요합니다. 따라서 이러한 렌더링 타임스탬프를 모니터링하는 것은 페이지 로드를 개선하고 회귀를 방지하는 데 중요합니다.
이 명세는 개발자와 분석 제공자에게 중요한 요소의 렌더링 타임스탬프를 측정하는 API를 제공합니다. 현재 실제 사용자에 대해 이러한 타임스탬프를 측정할 좋은 방법은 없습니다. 기존 접근 방식은 관찰자를 너무 일찍 등록하거나 상당한 DOM 조작을 필요로 합니다. 이러한 접근 방식은 § 4 보안 및 개인정보 보호 고려사항 절에서 논의됩니다.
웹 개발자는 자신의 사이트에서 중요한 사용자 상호작용의 전문가이므로, 자신이 관심을 가지는 요소가 무엇인지 사용자 에이전트에 알릴 수 있어야 합니다. 따라서 이 API는 웹 개발자가 주석을 단 요소에 대한 렌더링 타이밍 정보를 노출합니다.
1.1. 노출되는 요소
Element Timing API는 타이밍 적격 요소에 대한 타이밍 정보를 지원하며, 이는 [PAINT-TIMING]에서 정의됩니다.
"elementtiming" 콘텐츠 속성을 가진 요소는 이미지
요소 타이밍 보고 및 텍스트 요소 타이밍 보고 알고리즘에서 보고됩니다.
1.2. 사용 예제
다음 예제는 elementtiming 속성을 통해 관찰 대상으로 등록된 이미지와,
타이밍 정보를 수집하는 관찰자를 보여줍니다.
< img... elementtiming = 'foobar' /> < p elementtiming = 'important-paragraph' > 이것은 내가 관심 있는 텍스트입니다.</ p > ...< script > const observer= new PerformanceObserver(( list) => { let perfEntries= list. getEntries(); // 항목을 반복하면서 처리합니다. }); observer. observe({ type: 'element' , buffered: true }); </ script >
다음은 이 API를 사용해 렌더링 타임스탬프를 측정할 수 있고, 페이지 탐색과 비교해야 하는 요소의 예입니다:
-
쇼핑 사이트의 이미지 캐러셀에 있는 이미지.
-
뉴스 사이트 기사에 있는 주요 사진.
-
블로그 게시물의 제목.
-
백과사전 사이트 항목의 첫 번째 문단.
이 API는 렌더링 타임스탬프를 입력 타임스탬프와 비교함으로써 페이지 로드 외의 사용 사례도 가질 수 있습니다. 예를 들어 개발자는 위젯을 트리거하는 클릭 이후 해당 위젯이 표시되는 데 걸리는 시간을 모니터링할 수 있습니다.
2. 요소 타이밍
요소 타이밍은 다음 새 인터페이스를 포함합니다:
2.1.
PerformanceElementTiming
인터페이스
[Exposed =Window ]interface :PerformanceElementTiming PerformanceEntry {readonly attribute DOMHighResTimeStamp ;renderTime readonly attribute DOMHighResTimeStamp ;loadTime readonly attribute DOMRectReadOnly ;intersectionRect readonly attribute DOMString ;identifier readonly attribute unsigned long ;naturalWidth readonly attribute unsigned long ;naturalHeight readonly attribute DOMString ;id readonly attribute Element ?;element readonly attribute USVString ; [url Default ]object (); };toJSON PerformanceElementTiming includes PaintTimingMixin ;
PerformanceElementTiming
객체는 하나의 연결된 요소에 대한 타이밍 정보를 보고합니다.
각 PerformanceElementTiming
객체는 다음 연결된 개념을 가지며, 모두 처음에는 로 설정됩니다:
PerformanceElementTiming의
연결된 개념 및 일부 속성은 § 3.3 이미지 요소 타이밍 보고 및
§ 3.4 텍스트 요소 타이밍 보고의 처리 모델에서 지정됩니다.
entryType
속성의 getter는 DOMString
를 반환해야 합니다.
name
속성의 getter는 초기화된 값을 반환해야 합니다.
startTime
속성의 getter는 this의
renderTime이
0이 아니면 그 값을, 그렇지 않으면 this의 loadTime
값을 반환해야 합니다.
duration
속성의 getter는 0을 반환해야 합니다.
renderTime
속성 getter 단계는 this의 paint timing info가 주어졌을 때
기본 페인트 타임스탬프를 반환하는 것입니다.
loadTime
속성의 getter는 초기화된 값을 반환해야 합니다.
intersectionRect
속성은 초기화된 값을 반환해야 합니다.
identifier
속성의 getter는 초기화된 값을 반환해야 합니다.
naturalWidth
속성은 초기화된 값을 반환해야 합니다.
naturalHeight
속성은 초기화된 값을 반환해야 합니다.
id
속성의 getter는 초기화된 값을 반환해야 합니다.
element
속성의 getter는 다음 단계를 수행해야 합니다:
-
this의 element가 null이 주어졌을 때 페인트 타이밍에 노출되지 않으면 null을 반환합니다.
참고: 이는 더 이상 Document의
자손이 아닌 요소는 더 이상 element
속성 getter에 의해 반환되지 않음을 의미합니다.
url
속성의 getter는 다음 단계를 수행해야 합니다:
참고: 항목에서 과도한 메모리 사용을 피하기 위해 데이터 URL의 경우 URL을 잘라냅니다.
3. 처리 모델
참고: Element Timing API를 구현하는 사용자 에이전트는
Window
컨텍스트에 대해 supportedEntryTypes에
를 포함해야 합니다.
이를 통해 개발자는 요소 타이밍 지원 여부를 감지할 수 있습니다.
3.1. DOM 명세에 대한 수정
이 절은 [DOM] 명세가 수정되면 제거됩니다.
다음과 같이 Element
인터페이스를 확장합니다:
partial interface Element { [CEReactions ,Reflect ]attribute DOMString ; };elementTiming
3.2. 요소 타이밍 보고
Document
doc, [/=paint timing info=] paintTimingInfo, pending image records의 순서 있는 집합
paintedImages, 및 elements의
순서
있는 집합
paintedTextNodes가 주어졌을 때
요소
타이밍을 보고하라는 요청을 받으면, 다음 단계를 수행합니다:
-
paintedImages 안의 각 record에 대해:
-
record, paintTimingInfo, 및 doc를 전달하여 이미지 요소 타이밍 보고 알고리즘을 실행합니다.
-
-
paintedTextNodes 안의 각
Elementelement에 대해:-
element, paintTimingInfo, 및 doc가 주어졌을 때 텍스트 요소 타이밍 보고를 실행합니다.
-
3.3. 이미지 요소 타이밍 보고
Document
document가 주어졌을 때 이미지 요소 타이밍을 보고하라는 요청을 받으면, 다음 단계를 수행합니다:
-
record의 element의 "
elementtiming" 콘텐츠 속성이 없으면, 이 단계를 중단합니다. -
intersectionRect를 record의 element를 대상으로, viewport를 루트로 하여 intersection rect algorithm이 반환하는 값으로 둡니다.
-
document의 관련 Realm을 사용하여
PerformanceElementTiming객체 entry를 만들고 초기화하며, 그 paint timing info는 paintTimingInfo입니다.-
entry의
intersectionRect를 intersectionRect로 초기화합니다. -
entry의
identifier를 record의 element의 "elementtiming" 콘텐츠 속성으로 초기화합니다. -
entry의
naturalWidth및naturalHeight를img의naturalWidth및naturalHeight속성 getter와 동일한 단계를 실행하여 초기화하되, 이미지로 record의 request를 사용합니다.
-
entry PerformanceEntry를 큐에 넣습니다.
3.4. 텍스트 요소 타이밍 보고
Element
element, paint timing info paintTimingInfo 및 Document
document가 주어졌을 때 텍스트 요소 타이밍을 보고하라는 요청을 받으면, 다음 단계를 수행합니다:
-
element의 "
elementtiming" 콘텐츠 속성이 없으면, 이 단계를 중단합니다. -
intersectionRect를 빈 사각형으로 둡니다.
-
element의 소유 텍스트 노드 집합 안의 각
Textnode text에 대해:-
intersectionRect를 text의 border box와 intersectionRect를 포함하는 가장 작은 사각형이 되도록 확장합니다.
-
-
intersectionRect를 visual viewport와 교차시킵니다.
-
document의 관련 Realm을 사용하여
PerformanceElementTiming객체 entry를 만들고 초기화하며, 그 paint timing info는 paintTimingInfo입니다.-
entry의 element를 element로 초기화합니다.
-
entry의
loadTime을 0으로 초기화합니다. -
entry의
intersectionRect를 intersectionRect로 초기화합니다. -
entry의
identifier를 element의 "elementtiming" 콘텐츠 속성으로 초기화합니다. -
entry의
naturalWidth및naturalHeight를 0으로 초기화합니다. -
entry의
id를 element의 "id" 콘텐츠 속성으로 초기화합니다.
-
-
entry PerformanceEntry를 큐에 넣습니다.
4. 보안 및 개인정보 보호 고려사항
이 API는 교차 출처 이미지에 대한 일부 정보를 노출합니다. 특히 이미지의 리소스 로드 시간이 노출되며, 이는 개인정보 보호 우려의 원천이 될 수 있습니다.
그러나 ResourceTiming API가 이미 유사한 타임스탬프를 노출하므로,
이는 웹 플랫폼에 새로운 공격을 추가하지 않는 것으로 간주됩니다.
또한 onload 핸들러는 사용할 수 있을 때 로드 타이밍을 노출하며, 리소스 로드 시간은 이에
가까운 대리값입니다.
onload 핸들러의 시작 시점에 계산된 현재 고해상도 시간은 이미지 로드 시간을 제공할 것입니다.
loadTime은
onload 핸들러 없이도 매우 쉽게 얻을 수 있으므로 이를 노출하기로 선택했습니다.
또한 이미지 onload 핸들러나 ResourceTiming이 제공하는 누출을 제거하기 위한 수정은
이 API가 제공하는 누출도 수정할 수 있다고 생각합니다.
renderTime
(표시 타임스탬프)는 실제로 새로 노출되는 정보입니다. 구현은 교차 출처
이미지 간 디코딩 시간 차이를 노출하지 않도록, 이 타임스탬프를 적어도 4밀리초 해상도로
더 거칠게 만들 것을 권고받습니다. `Timing-Allow-Origin` 같은 다른 검사는 동일 출처 이미지와
교차 출처 이미지가 동시에 렌더링되므로 여기서는 동작하지 않는다는 점에 유의하십시오.
어쨌든 거친 renderTime을
노출하는 것은 실질적인 공격 벡터가 아닙니다. 이미지 자연 크기
및 로딩 시간이 다른 방식으로 노출되기 때문입니다.
// 공격자 프레임 안.< iframe src = attack.html ></ iframe > < script > window. onmessage= e=> { let timestamp= e. data; // 'victim.jpg'의 표시 타임스탬프를 획득했습니다! } </ script > // attack.html iframe 안.< img src = 'victim.jpg' /> < script > // onload까지 또는 PaintTiming 항목이 보일 어떤 시점까지 기다립니다. onload() => { let entry= performance. getEntriesByType( 'paint' )[ 0 ]; top. postMessage( entry. startTime, '*' ); } </ script >
여기서 노출되는 또 다른 중요 매개변수는 intersectionRect입니다.
이는 예를 들어 IntersectionObserver를
사용하여 이미 폴리필할 수 있습니다.
폴리필 과정도 유사합니다. 대상 이미지 또는 텍스트 콘텐츠의 onload 핸들러에서 IntersectionObserver를
추가합니다.
이 해결책은 콘텐츠가 로드된 뒤 관찰자를 등록해야 하므로 비효율적이지만,
여전히 같은 수준의 정확도를 제공해야 합니다.
이미지가 완전히 표시될 때까지만 rect를 계산한다면, 그 시점 이후에야 항목을 노출할 수 있게 됩니다.
이미지의 렌더링 타임스탬프를 노출하고 싶지 않다면, 항목을
PerformanceObserver로
즉시 디스패치하는 것이 바람직합니다.
기다렸다가 요소 타이밍 보고
알고리즘 중에 모든 항목을 노출한다고 가정해 보겠습니다.
공격자는 이미지의 렌더링 타임스탬프에 대한 중요 정보를 추론할 수 있습니다.
이는 해당 이미지의 타이밍만 관찰함으로써 이루어질 수 있습니다.
수신한 PerformanceElementTiming
항목의 멤버로 타임스탬프가 노출되지 않더라도,
다음 렌더링 업데이트 단계까지 기다린다는 사실은,
공격자가 항목을 받은 시간을 측정하여 매우 느린 렌더링 시간과 매우 빠른 렌더링 시간을
구별할 수 있음을 의미합니다.
이는 의도치 않게 이미지의 표시 타이밍 일부를 누출할 수 있습니다.