Skip to content

Commit f6a67dc

Browse files
Add navigationId to PerformanceEntry (#192)
Add id and navigationId fields to PerformanceEntry. These are integers, used to uniquely identify timeline entries, so that they can be referred to in other entries. The initial use case for this is to track navigation-like events within a page's lifetime. For this, the navigationId field is used, in each entry, to refer to the most recent navigation (or back-forward-cache restoration, or soft navigation) which had occurred in the page. --------- Co-authored-by: Marcos Cáceres <marcos@marcosc.com>
1 parent 3984a34 commit f6a67dc

File tree

2 files changed

+103
-0
lines changed

2 files changed

+103
-0
lines changed

explainer.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,12 @@ In order to prevent the user agent from storing too much performance data in mem
5555
This specification defines the `PerformanceEntry` interface, which is used to host performance data of the web application.
5656
A single `PerformanceEntry` object corresponds to one nugget of information about the performance of the website.
5757
The entry has the following attributes:
58+
* `id`: an integer identifying this `PerformanceEntry` object.
5859
* `name`: a string identifier for the object, also used to filter entries in the `getEntriesByName()` method.
5960
* `entryType`: a string representing the type of performance data being exposed. It is also used to filter entries in the `getEntriesByType()` method and in the `PerformanceObserver`.
6061
* `startTime`: a timestamp representing the starting point for the performance data being recorded. The semantics of this attribute depend on the `entryType`.
6162
* `duration`: a time duration representing the duration of the performance data being recorded. The semantics of this one also depend on the `entryType`.
63+
* `navigationId`: an integer identifying (by `id`) the `PerformanceEntry` object corresponding to last navigation or navigation-like event that had occurred in the document at the time that this `PerformanceEntry` object was recorded.
6264

6365
If these sound abstract, it’s because they are.
6466
A specification whose goal is to expose new measurements to web developers will define a new interface which extends `PerformanceEntry`.
@@ -150,6 +152,20 @@ For entryTypes with a fixed amount of entries, like Paint Timing, using the poll
150152
At the same time, the callback is more useful for cases where there is varying amount of entries of the given entryType, like in Resource Timing.
151153
The web performance monitoring service can process all the performance information while the page is still running and only has to do very minimal work when the data needs to be reported.
152154

155+
## Page lifetime issues
156+
When this API was originally designed, documents had a relatively simple lifecycle: they were
157+
loaded when the user navigated to them, and unloaded when the user navigated away, with the
158+
JavaScript environment being torn down at that time. Since then, the sitution has become more
159+
complex, with many browsers introducing a back-forward cache, with which a user can return to
160+
a document which they have previously navigated away from. The web has also seen a rise in
161+
popularity of Single Page Apps, where what appears to the user to be a navigation is actually
162+
just a change in state of a running page. In both of these situations, a navigation (or what
163+
appears to the user as a navigation) can occur without the performance timeline being reset.
164+
In order to allow developers to reason about such events during the life of a page, some
165+
PerformanceEntry objects mark navigations, or navigation-like events. All PerformanceEntry
166+
objects include a navigation ID field, which ties each PerformanceEntry to the most recent
167+
navigation entry which had occurred before the entry was generated.
168+
153169
# Standards Status
154170
The Performance Timeline specification is widely approved.
155171
There are differences in what kinds of performance data is exposed on different user agents, but this specification does not concern itself with that, and that is delegated to the new specifications that describe new data.

index.html

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@
6767
</li>
6868
<li>Exposes {{PerformanceEntry}} in Web Workers [[WORKERS]];
6969
</li>
70+
<li>Formalizes support for multiple navigation events over a document's
71+
lifetime.
72+
</li>
7073
<li>Adds support for {{PerformanceObserver}}.
7174
</li>
7275
</ul>
@@ -243,6 +246,15 @@ <h2><dfn>Performance Timeline</dfn></h2>
243246
<li>An integer <dfn>dropped entries count</dfn> that is initially 0.</li>
244247
</ul>
245248
</li>
249+
<li>An integer <dfn>last performance entry id</dfn> that is initially set
250+
to a random integer between 100 and 10000.
251+
</li>
252+
</ul>
253+
<p>Each <a>Document</a> has:</p>
254+
<ul>
255+
<li>A <dfn>most recent navigation</dfn>, which is a <a>PerformanceEntry</a>,
256+
initially unset.
257+
</li>
246258
</ul>
247259
<p>In order to get the <dfn>relevant performance entry tuple</dfn>, given
248260
<var>entryType</var> and <var>globalObject</var> as input, run the
@@ -301,13 +313,19 @@ <h2>The <dfn>PerformanceEntry</dfn> interface</h2>
301313
<pre class='idl'>
302314
[Exposed=(Window,Worker)]
303315
interface PerformanceEntry {
316+
readonly attribute unsigned long long id;
304317
readonly attribute DOMString name;
305318
readonly attribute DOMString entryType;
306319
readonly attribute DOMHighResTimeStamp startTime;
307320
readonly attribute DOMHighResTimeStamp duration;
321+
readonly attribute unsigned long long navigationId;
308322
[Default] object toJSON();
309323
};</pre>
310324
<dl>
325+
<dt><dfn>id</dfn></dt>
326+
<dd>
327+
This attribute MUST return the value of <a>this</a>'s <a>id</a>.
328+
</dd>
311329
<dt><dfn>name</dfn></dt>
312330
<dd>
313331
This attribute MUST return an identifier for this
@@ -341,6 +359,10 @@ <h2>The <dfn>PerformanceEntry</dfn> interface</h2>
341359
duration concept doesn't apply, a performance metric may choose to
342360
return a `duration` of <code>0</code>.
343361
</dd>
362+
<dt><dfn>navigationId</dfn></dt>
363+
<dd>
364+
This attribute MUST return the value of <a>this</a>'s <a>navigationId</a>.
365+
</dd>
344366
</dl>
345367
<p>When <dfn>toJSON</dfn> is called, run [[WebIDL]]'s <a>default toJSON
346368
steps</a>.</p>
@@ -660,6 +682,12 @@ <h2>Queue a <code>PerformanceEntry</code></h2>
660682
<p>To <dfn class="export">queue a PerformanceEntry</dfn> (<var>newEntry</var>), run
661683
these steps:</p>
662684
<ol>
685+
<li>If <var>newEntry</var>'s {{PerformanceEntry/id}} is unset:
686+
<ol>
687+
<li>Let <var>id</var> be the result of running <a>generate an id</a> for <var>newEntry</var>.</li>
688+
<li>Set <var>newEntry</var>'s {{PerformanceEntry/id}} to <var>id</var>.</li>
689+
</ol>
690+
</li>
663691
<li>Let <var>interested observers</var> be an initially empty set of
664692
<a>PerformanceObserver</a> objects.
665693
</li>
@@ -669,6 +697,15 @@ <h2>Queue a <code>PerformanceEntry</code></h2>
669697
<li>Let <var>relevantGlobal</var> be <var>newEntry</var>'s <a>relevant
670698
global object</a>.
671699
</li>
700+
<li>If <var>relevantGlobal</var> has an [=associated document=]:
701+
<ol>
702+
<li>Set <var>newEntry</var>'s <a
703+
data-lt="PerformanceEntry.navigationId">navigationId</a> to the value of
704+
<var>relevantGlobal</var>'s [=associated document=]'s [=most recent navigation=]'s {{PerformanceEntry/id}}.</li>
705+
</ol>
706+
</li>
707+
<li>Otherwise, set <var>newEntry</var>'s <a
708+
data-lt="PerformanceEntry.navigationId">navigationId</a> to null.</li>
672709
<li>For each <a>registered performance observer</a> <var>regObs</var> in
673710
<var>relevantGlobal</var>'s <a>list of registered performance observer objects</a>:
674711
<ol>
@@ -714,6 +751,25 @@ <h2>Queue a <code>PerformanceEntry</code></h2>
714751
</li>
715752
</ol>
716753
</section>
754+
<section data-link-for="PerformanceObserver">
755+
<h2>Queue a navigation <code>PerformanceEntry</code></h2>
756+
<p>To <dfn class="export">queue a navigation PerformanceEntry</dfn> (<var>newEntry</var>), run
757+
these steps:</p>
758+
<ol>
759+
<li>Let <var>id</var> be the result of running <a>generate an id</a> for <var>newEntry</var>.</li>
760+
<li>Let <var>relevantGlobal</var> be <var>newEntry</var>'s <a>relevant
761+
global object</a>.
762+
</li>
763+
<li>Set <var>newEntry</var>'s {{PerformanceEntry/id}} to <var>id</var>.</li>
764+
<li>Set <var>newEntry</var>'s {{PerformanceEntry/navigationId}} to <var>id</var>.</li>
765+
<li>If <var>relevantGlobal</var> has an [=associated document=]:
766+
<ol>
767+
<li>Set <var>relevantGlobal</var>'s [=associated document=]'s [=most recent navigation=] to <var>newEntry</var>.</li>
768+
</ol>
769+
</li>
770+
<li><a>Queue a PerformanceEntry</a> with <var>newEntry</var> as input.</li>
771+
</ol>
772+
</section>
717773
<section data-link-for="PerformanceObserver">
718774
<h2>Queue the PerformanceObserver task</h2>
719775
<p>When asked to <dfn>queue the PerformanceObserver task</dfn>, given
@@ -883,6 +939,28 @@ <h2>Determine if a performance entry buffer is full</h2>
883939
<li>Return true.</li>
884940
</ol>
885941
</section>
942+
<section data-link-for="PerformanceEntry">
943+
<h2>Generate a Performance Entry id</h2>
944+
<p>When asked to <dfn class="export">generate an id</dfn> for a
945+
<a>PerformanceEntry</a> <var>entry</a>, run the following steps:</p>
946+
<ol>
947+
<li>Let <var>relevantGlobal</var> be <var>entry</var>'s <a>relevant
948+
global object</a>.
949+
<li>Increase <var>relevantGlobal</var>'s <a>last performance entry
950+
id</a> by a small number chosen by the user agent.</li>
951+
<li>Return <var>relevantGlobal</var>'s <a>last performance entry id</a>.
952+
</ol>
953+
<p>A user agent may choose to increase the <a>last performance entry
954+
id</a>it by a small random integer every time. A user agent must not pick
955+
a single global random integer and increase the <a>last performance entry
956+
id</a> of all global objects by that amount because this could introduce
957+
cross origin leaks.
958+
</p>
959+
<p class="note">The <a>last performance entry id</a> has an initial random
960+
value, and is increased by a small number chosen by the user agent instead
961+
of 1 to discourage developers from considering it as a counter of the
962+
number of entries that have been generated in the web application.</p>
963+
</section>
886964
</section>
887965
<section id="privacy">
888966
<h3>Privacy Considerations</h3>
@@ -891,6 +969,15 @@ <h3>Privacy Considerations</h3>
891969
refer to [[HR-TIME-3]] for privacy considerations of exposing high-resoluting timing
892970
information. Each new specification introducing new performance entries should have its own
893971
privacy considerations as well.</p>
972+
<p>The <a>last performance entry id</a> is deliberately initialized to a
973+
random value, and is incremented by another small value every time a new
974+
{{PerformanceEntry}} is queued. User agents may choose to use a consistent
975+
increment for all users, or may pick a different increment for each
976+
<a>global object</a>, or may choose a new random increment for each
977+
{{PerformanceEntry}}. However, in order to prevent cross-origin leaks, and
978+
ensure that this does not enable fingerprinting, user agents must not just
979+
pick a unique random integer, and use it as a consistent increment for all
980+
{{PerformanceEntry}} objects across all <a>global objects</a>.
894981
</section>
895982
<section id="security">
896983
<h3>Security Considerations</h3>

0 commit comments

Comments
 (0)