From 73ad3f405a65add810a92f1b885d646a7fa9f9fc Mon Sep 17 00:00:00 2001 From: HoonDongKang Date: Sat, 1 Aug 2026 14:03:01 +0900 Subject: [PATCH] perf_hooks: add PerformanceEntry id and navigationId Add the PerformanceEntry id and navigationId attributes required by the Performance Timeline IDL. Entries get an id when queued, following the Performance Timeline queueing algorithm. Update the performance-timeline WPT status now that idlharness.any.js passes for these attributes. Refs: https://w3c.github.io/performance-timeline/#performanceentry Refs: https://w3c.github.io/performance-timeline/#queue-a-performanceentry Refs: https://w3c.github.io/performance-timeline/#generate-a-performance-entry-id Signed-off-by: HoonDongKang --- lib/internal/perf/observe.js | 3 +++ lib/internal/perf/performance_entry.js | 32 +++++++++++++++++++++++ test/wpt/status/performance-timeline.json | 9 ------- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/lib/internal/perf/observe.js b/lib/internal/perf/observe.js index d284d4a54fbc..32a71e2d984e 100644 --- a/lib/internal/perf/observe.js +++ b/lib/internal/perf/observe.js @@ -38,6 +38,7 @@ const { const { isPerformanceEntry, createPerformanceNodeEntry, + markPerformanceEntryQueued, } = require('internal/perf/performance_entry'); const { @@ -388,6 +389,8 @@ function enqueue(entry) { if (!isPerformanceEntry(entry)) throw new ERR_INVALID_ARG_TYPE('entry', 'PerformanceEntry', entry); + markPerformanceEntryQueued(entry); + for (const obs of kObservers) { obs[kMaybeBuffer](entry); } diff --git a/lib/internal/perf/performance_entry.js b/lib/internal/perf/performance_entry.js index b9ac2ad1d0b2..69e2194d6b1a 100644 --- a/lib/internal/perf/performance_entry.js +++ b/lib/internal/perf/performance_entry.js @@ -1,6 +1,8 @@ 'use strict'; const { + MathFloor, + MathRandom, ObjectDefineProperties, Symbol, } = primordials; @@ -20,12 +22,27 @@ const { validateThisInternalField } = require('internal/validators'); const { inspect } = require('util'); const kName = Symbol('PerformanceEntry.Name'); +const kId = Symbol('PerformanceEntry.Id'); const kEntryType = Symbol('PerformanceEntry.EntryType'); const kStartTime = Symbol('PerformanceEntry.StartTime'); const kDuration = Symbol('PerformanceEntry.Duration'); +const kNavigationId = Symbol('PerformanceEntry.NavigationId'); const kDetail = Symbol('NodePerformanceEntry.Detail'); const kSkipThrow = Symbol('kSkipThrow'); +let lastPerformanceEntryId = MathFloor(MathRandom() * 9901) + 100; + +function nextPerformanceEntryId() { + return ++lastPerformanceEntryId; +} + +function markPerformanceEntryQueued(entry) { + validateThisInternalField(entry, kName, 'PerformanceEntry'); + if (entry[kId] === 0) { + entry[kId] = nextPerformanceEntryId(); + } +} + function isPerformanceEntry(obj) { return obj?.[kName] !== undefined; } @@ -43,9 +60,16 @@ class PerformanceEntry { } this[kName] = name; + this[kId] = 0; this[kEntryType] = type; this[kStartTime] = start; this[kDuration] = duration; + this[kNavigationId] = 0; + } + + get id() { + validateThisInternalField(this, kName, 'PerformanceEntry'); + return this[kId]; } get name() { @@ -68,6 +92,11 @@ class PerformanceEntry { return this[kDuration]; } + get navigationId() { + validateThisInternalField(this, kName, 'PerformanceEntry'); + return this[kNavigationId]; + } + [kInspect](depth, options) { if (depth < 0) return this; @@ -90,10 +119,12 @@ class PerformanceEntry { } } ObjectDefineProperties(PerformanceEntry.prototype, { + id: kEnumerableProperty, name: kEnumerableProperty, entryType: kEnumerableProperty, startTime: kEnumerableProperty, duration: kEnumerableProperty, + navigationId: kEnumerableProperty, toJSON: kEnumerableProperty, }); @@ -134,6 +165,7 @@ module.exports = { createPerformanceEntry, PerformanceEntry, isPerformanceEntry, + markPerformanceEntryQueued, PerformanceNodeEntry, createPerformanceNodeEntry, kSkipThrow, diff --git a/test/wpt/status/performance-timeline.json b/test/wpt/status/performance-timeline.json index 799ee97538d0..74e0da93cb23 100644 --- a/test/wpt/status/performance-timeline.json +++ b/test/wpt/status/performance-timeline.json @@ -7,15 +7,6 @@ ] } }, - "idlharness.any.js": { - "fail": { - "note": "not implemented", - "expected": [ - "PerformanceEntry interface: attribute id", - "PerformanceEntry interface: attribute navigationId" - ] - } - }, "navigation-id.helper.js": { "skip": "This is not a test file." },