From f6a67dc678fce0b0e972d377b6d05ed457f63a21 Mon Sep 17 00:00:00 2001
From: Ian Clelland
Date: Wed, 11 Oct 2023 11:38:08 -0400
Subject: [PATCH] Add navigationId to PerformanceEntry (#192)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
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
---
explainer.md | 16 ++++++++++
index.html | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 103 insertions(+)
diff --git a/explainer.md b/explainer.md
index 7c6d672..2a06581 100644
--- a/explainer.md
+++ b/explainer.md
@@ -55,10 +55,12 @@ In order to prevent the user agent from storing too much performance data in mem
This specification defines the `PerformanceEntry` interface, which is used to host performance data of the web application.
A single `PerformanceEntry` object corresponds to one nugget of information about the performance of the website.
The entry has the following attributes:
+* `id`: an integer identifying this `PerformanceEntry` object.
* `name`: a string identifier for the object, also used to filter entries in the `getEntriesByName()` method.
* `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`.
* `startTime`: a timestamp representing the starting point for the performance data being recorded. The semantics of this attribute depend on the `entryType`.
* `duration`: a time duration representing the duration of the performance data being recorded. The semantics of this one also depend on the `entryType`.
+* `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.
If these sound abstract, it’s because they are.
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
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.
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.
+## Page lifetime issues
+When this API was originally designed, documents had a relatively simple lifecycle: they were
+loaded when the user navigated to them, and unloaded when the user navigated away, with the
+JavaScript environment being torn down at that time. Since then, the sitution has become more
+complex, with many browsers introducing a back-forward cache, with which a user can return to
+a document which they have previously navigated away from. The web has also seen a rise in
+popularity of Single Page Apps, where what appears to the user to be a navigation is actually
+just a change in state of a running page. In both of these situations, a navigation (or what
+appears to the user as a navigation) can occur without the performance timeline being reset.
+In order to allow developers to reason about such events during the life of a page, some
+PerformanceEntry objects mark navigations, or navigation-like events. All PerformanceEntry
+objects include a navigation ID field, which ties each PerformanceEntry to the most recent
+navigation entry which had occurred before the entry was generated.
+
# Standards Status
The Performance Timeline specification is widely approved.
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.
diff --git a/index.html b/index.html
index 2321374..58bd63e 100644
--- a/index.html
+++ b/index.html
@@ -67,6 +67,9 @@
Exposes {{PerformanceEntry}} in Web Workers [[WORKERS]];
+ Formalizes support for multiple navigation events over a document's
+ lifetime.
+
Adds support for {{PerformanceObserver}}.
@@ -243,6 +246,15 @@ Performance Timeline
An integer dropped entries count that is initially 0.
+ An integer last performance entry id that is initially set
+ to a random integer between 100 and 10000.
+
+
+ Each Document has:
+
In order to get the relevant performance entry tuple, given
entryType and globalObject as input, run the
@@ -301,13 +313,19 @@
The PerformanceEntry interface
[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();
};
+ - id
+ -
+ This attribute MUST return the value of this's id.
+
- name
-
This attribute MUST return an identifier for this
@@ -341,6 +359,10 @@
The PerformanceEntry interface
duration concept doesn't apply, a performance metric may choose to
return a `duration` of 0
.
+ - navigationId
+ -
+ This attribute MUST return the value of this's navigationId.
+
When toJSON is called, run [[WebIDL]]'s default toJSON
steps.
@@ -660,6 +682,12 @@ Queue a PerformanceEntry
To queue a PerformanceEntry (newEntry), run
these steps:
+ - If newEntry's {{PerformanceEntry/id}} is unset:
+
+ - Let id be the result of running generate an id for newEntry.
+ - Set newEntry's {{PerformanceEntry/id}} to id.
+
+
- Let interested observers be an initially empty set of
PerformanceObserver objects.
@@ -669,6 +697,15 @@ Queue a PerformanceEntry
- Let relevantGlobal be newEntry's relevant
global object.
+ - If relevantGlobal has an [=associated document=]:
+
+ - Set newEntry's navigationId to the value of
+ relevantGlobal's [=associated document=]'s [=most recent navigation=]'s {{PerformanceEntry/id}}.
+
+
+ - Otherwise, set newEntry's navigationId to null.
- For each registered performance observer regObs in
relevantGlobal's list of registered performance observer objects:
@@ -714,6 +751,25 @@ Queue a PerformanceEntry
+
+ Queue a navigation PerformanceEntry
+ To queue a navigation PerformanceEntry (newEntry), run
+ these steps:
+
+ - Let id be the result of running generate an id for newEntry.
+ - Let relevantGlobal be newEntry's relevant
+ global object.
+
+ - Set newEntry's {{PerformanceEntry/id}} to id.
+ - Set newEntry's {{PerformanceEntry/navigationId}} to id.
+ - If relevantGlobal has an [=associated document=]:
+
+ - Set relevantGlobal's [=associated document=]'s [=most recent navigation=] to newEntry.
+
+
+ - Queue a PerformanceEntry with newEntry as input.
+
+
Queue the PerformanceObserver task
When asked to queue the PerformanceObserver task, given
@@ -883,6 +939,28 @@
Determine if a performance entry buffer is full
Return true.
+
+ Generate a Performance Entry id
+ When asked to generate an id for a
+ PerformanceEntry entry, run the following steps:
+
+ - Let relevantGlobal be entry's relevant
+ global object.
+
- Increase relevantGlobal's last performance entry
+ id by a small number chosen by the user agent.
+ - Return relevantGlobal's last performance entry id.
+
+ A user agent may choose to increase the last performance entry
+ idit by a small random integer every time. A user agent must not pick
+ a single global random integer and increase the last performance entry
+ id of all global objects by that amount because this could introduce
+ cross origin leaks.
+
+ The last performance entry id has an initial random
+ value, and is increased by a small number chosen by the user agent instead
+ of 1 to discourage developers from considering it as a counter of the
+ number of entries that have been generated in the web application.
+
Privacy Considerations
@@ -891,6 +969,15 @@ Privacy Considerations
refer to [[HR-TIME-3]] for privacy considerations of exposing high-resoluting timing
information. Each new specification introducing new performance entries should have its own
privacy considerations as well.
+ The last performance entry id is deliberately initialized to a
+ random value, and is incremented by another small value every time a new
+ {{PerformanceEntry}} is queued. User agents may choose to use a consistent
+ increment for all users, or may pick a different increment for each
+ global object, or may choose a new random increment for each
+ {{PerformanceEntry}}. However, in order to prevent cross-origin leaks, and
+ ensure that this does not enable fingerprinting, user agents must not just
+ pick a unique random integer, and use it as a consistent increment for all
+ {{PerformanceEntry}} objects across all global objects.