Skip to content

Commit bfa9754

Browse files
committed
perf_hooks: fix observable when using resource
1 parent b728149 commit bfa9754

File tree

5 files changed

+156
-39
lines changed

5 files changed

+156
-39
lines changed

lib/internal/perf/observe.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -343,8 +343,9 @@ function enqueue(entry) {
343343
buffer = markEntryBuffer;
344344
} else if (entryType === 'measure') {
345345
buffer = measureEntryBuffer;
346-
} else {
346+
} else if (entryType === 'resource') {
347347
buffer = resourceTimingBuffer;
348+
} else {
348349
return;
349350
}
350351

lib/internal/perf/resource_timing.js

+12-12
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,27 @@
1-
// https://github.com/nodejs/undici/issues/952
1+
'use strict';
22
// https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming
33

44
const { InternalPerformanceEntry } = require('internal/perf/performance_entry');
55
const { SymbolToStringTag } = primordials;
6-
const assert = require('assert')
6+
const assert = require('internal/assert');
77
const { enqueue } = require('internal/perf/observe');
8+
const { Symbol } = primordials;
89

910
const kCacheMode = Symbol('kCacheMode');
1011
const kRequestedUrl = Symbol('kRequestedUrl');
1112
const kTimingInfo = Symbol('kTimingInfo');
1213
const kInitiatorType = Symbol('kInitiatorType');
1314

1415
class PerformanceResourceTiming extends InternalPerformanceEntry {
15-
constructor(requestedUrl, start, initiatorType, timingInfo, cacheMode = "") {
16+
constructor(requestedUrl, start, initiatorType, timingInfo, cacheMode = '') {
1617
super(requestedUrl, 'resource', start);
1718
// https://w3c.github.io/resource-timing/#dfn-setup-the-resource-timing-entry
18-
assert.ok(cacheMode === "" || cacheMode === "local")
19-
this[kInitiatorType] = initiatorType
20-
this[kRequestedUrl] = requestedUrl
19+
assert.ok(cacheMode === '' || cacheMode === 'local');
20+
this[kInitiatorType] = initiatorType;
21+
this[kRequestedUrl] = requestedUrl;
2122
// https://fetch.spec.whatwg.org/#fetch-timing-info
22-
this[kTimingInfo] = timingInfo
23-
this[kCacheMode] = cacheMode
23+
this[kTimingInfo] = timingInfo;
24+
this[kCacheMode] = cacheMode;
2425
}
2526

2627
get [SymbolToStringTag]() {
@@ -118,7 +119,7 @@ class PerformanceResourceTiming extends InternalPerformanceEntry {
118119
entryType: this.entryType,
119120
startTime: this.startTime,
120121
duration: this.duration,
121-
}
122+
};
122123
}
123124
}
124125

@@ -128,14 +129,13 @@ function markResourceTiming(
128129
requestedUrl,
129130
initiatorType,
130131
global,
131-
cacheMode
132+
cacheMode,
132133
) {
133134
// TODO(rafaelgss): Probably must have some asserts here for:
134135
// - timingInfo
135136
// - requestedUrl
136137
// - initiatorType
137138
// - cacheMode
138-
139139
// 1. Create a PerformanceResourceTiming object entry in global's realm.
140140
// TODO(rafaelgss): why and how should I put `resource` into global object?
141141
const resource = new PerformanceResourceTiming(
@@ -144,7 +144,7 @@ function markResourceTiming(
144144
timingInfo.startTime,
145145
initiatorType,
146146
timingInfo,
147-
cacheMode
147+
cacheMode,
148148
);
149149
enqueue(resource);
150150
return resource;

lib/perf_hooks.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const {
99
} = internalBinding('performance');
1010

1111
const { PerformanceEntry } = require('internal/perf/performance_entry');
12-
const { PerformanceResourceTiming } = require('internal/perf/resource_timing')
12+
const { PerformanceResourceTiming } = require('internal/perf/resource_timing');
1313
const {
1414
PerformanceObserver,
1515
PerformanceObserverEntryList,

test/parallel/test-bootstrap-modules.js

+1
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ const expectedModules = new Set([
9898
'NativeModule internal/perf/performance',
9999
'NativeModule internal/perf/timerify',
100100
'NativeModule internal/perf/usertiming',
101+
'NativeModule internal/perf/resource_timing',
101102
'NativeModule internal/perf/utils',
102103
'NativeModule internal/priority_queue',
103104
'NativeModule internal/process/esm_loader',

test/parallel/test-perf-hooks-resourcetiming.js

+140-25
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,17 @@ function createTimingInfo({
3333
}) {
3434
if (finalConnectionTimingInfo !== null) {
3535
finalConnectionTimingInfo.domainLookupStartTime =
36-
finalConnectionTimingInfo.domainLookupStartTime || 0
36+
finalConnectionTimingInfo.domainLookupStartTime || 0;
3737
finalConnectionTimingInfo.domainLookupEndTime =
38-
finalConnectionTimingInfo.domainLookupEndTime || 0
38+
finalConnectionTimingInfo.domainLookupEndTime || 0;
3939
finalConnectionTimingInfo.connectionStartTime =
40-
finalConnectionTimingInfo.connectionStartTime || 0
40+
finalConnectionTimingInfo.connectionStartTime || 0;
4141
finalConnectionTimingInfo.connectionEndTime =
42-
finalConnectionTimingInfo.connectionEndTime || 0
42+
finalConnectionTimingInfo.connectionEndTime || 0;
4343
finalConnectionTimingInfo.secureConnectionStartTime =
44-
finalConnectionTimingInfo.secureConnectionStartTime || 0
44+
finalConnectionTimingInfo.secureConnectionStartTime || 0;
4545
finalConnectionTimingInfo.ALPNNegotiatedProtocol =
46-
finalConnectionTimingInfo.ALPNNegotiatedProtocol || []
46+
finalConnectionTimingInfo.ALPNNegotiatedProtocol || [];
4747
}
4848
return {
4949
startTime,
@@ -57,27 +57,53 @@ function createTimingInfo({
5757
encodedBodySize,
5858
decodedBodySize,
5959
finalConnectionTimingInfo,
60-
}
60+
};
6161
}
6262

63+
// Using performance.getEntries*()
6364
{
64-
const obs = new PerformanceObserver(common.mustCall((list) => {
65-
{
66-
const entries = list.getEntries();
67-
assert.strictEqual(entries.length, 1);
68-
}
69-
{
70-
const entries = list.getEntriesByType('resource');
71-
assert.strictEqual(entries.length, 1);
72-
}
73-
{
74-
const entries = list.getEntriesByName('http://localhost:8080');
75-
assert.strictEqual(entries.length, 1);
76-
}
77-
obs.disconnect();
78-
}));
79-
obs.observe({ entryTypes: ['resource'] });
65+
const timingInfo = createTimingInfo({ finalConnectionTimingInfo: {} });
66+
const customGlobal = {};
67+
const requestedUrl = 'http://localhost:8080';
68+
const cacheMode = 'local';
69+
const initiatorType = 'fetch';
70+
const resource = markResourceTiming(
71+
timingInfo,
72+
requestedUrl,
73+
initiatorType,
74+
customGlobal,
75+
cacheMode,
76+
);
77+
78+
assert(resource instanceof PerformanceEntry);
79+
assert(resource instanceof PerformanceResourceTiming);
80+
81+
{
82+
const entries = performance.getEntries();
83+
assert.strictEqual(entries.length, 1);
84+
assert(entries[0] instanceof PerformanceResourceTiming);
85+
}
86+
87+
{
88+
const entries = performance.getEntriesByType('resource');
89+
assert.strictEqual(entries.length, 1);
90+
assert(entries[0] instanceof PerformanceResourceTiming);
91+
}
92+
93+
{
94+
const entries = performance.getEntriesByName(resource.name);
95+
assert.strictEqual(entries.length, 1);
96+
assert(entries[0] instanceof PerformanceResourceTiming);
97+
}
98+
99+
clearResourceTimings();
100+
assert.strictEqual(performance.getEntries().length, 0);
101+
}
102+
103+
// Assert resource data based in timingInfo
80104

105+
// default values
106+
{
81107
const timingInfo = createTimingInfo({ finalConnectionTimingInfo: {} });
82108
const customGlobal = {};
83109
const requestedUrl = 'http://localhost:8080';
@@ -108,14 +134,14 @@ function createTimingInfo({
108134
assert.strictEqual(resource.connectStart, 0);
109135
assert.strictEqual(resource.connectEnd, 0);
110136
assert.strictEqual(resource.secureConnectionStart, 0);
111-
assert.deepEqual(resource.nextHopProtocol, []);
137+
assert.deepStrictEqual(resource.nextHopProtocol, []);
112138
assert.strictEqual(resource.requestStart, 0);
113139
assert.strictEqual(resource.responseStart, 0);
114140
assert.strictEqual(resource.responseEnd, 0);
115141
assert.strictEqual(resource.encodedBodySize, 0);
116142
assert.strictEqual(resource.decodedBodySize, 0);
117143
assert.strictEqual(resource.transferSize, 0);
118-
assert.deepEqual(resource.toJSON(), {
144+
assert.deepStrictEqual(resource.toJSON(), {
119145
initiatorType,
120146
requestedUrl,
121147
cacheMode,
@@ -124,4 +150,93 @@ function createTimingInfo({
124150
startTime: timingInfo.startTime,
125151
duration: 0
126152
});
153+
154+
assert(resource instanceof PerformanceEntry);
155+
assert(resource instanceof PerformanceResourceTiming);
156+
157+
clearResourceTimings();
158+
const entries = performance.getEntries();
159+
assert.strictEqual(entries.length, 0);
160+
}
161+
162+
// custom getters math
163+
{
164+
const timingInfo = createTimingInfo({
165+
endTime: 100,
166+
startTime: 50,
167+
encodedBodySize: 150,
168+
});
169+
const customGlobal = {};
170+
const requestedUrl = 'http://localhost:8080';
171+
const cacheMode = '';
172+
const initiatorType = 'fetch';
173+
const resource = markResourceTiming(
174+
timingInfo,
175+
requestedUrl,
176+
initiatorType,
177+
customGlobal,
178+
cacheMode,
179+
);
180+
181+
assert(resource instanceof PerformanceEntry);
182+
assert(resource instanceof PerformanceResourceTiming);
183+
184+
assert.strictEqual(resource.entryType, 'resource');
185+
assert.strictEqual(resource.name, requestedUrl);
186+
assert.ok(typeof resource.cacheMode === 'undefined', 'cacheMode does not have a getter');
187+
assert.strictEqual(resource.startTime, timingInfo.startTime);
188+
// Duration should be the timingInfo endTime - startTime
189+
assert.strictEqual(resource.duration, 50);
190+
// TransferSize should be encodedBodySize + 300 when cacheMode is empty
191+
assert.strictEqual(resource.transferSize, 450);
192+
193+
assert(resource instanceof PerformanceEntry);
194+
assert(resource instanceof PerformanceResourceTiming);
195+
196+
clearResourceTimings();
197+
const entries = performance.getEntries();
198+
assert.strictEqual(entries.length, 0);
199+
}
200+
201+
// Using PerformanceObserver
202+
{
203+
const obs = new PerformanceObserver(common.mustCall((list) => {
204+
{
205+
const entries = list.getEntries();
206+
assert.strictEqual(entries.length, 1);
207+
assert(entries[0] instanceof PerformanceResourceTiming);
208+
}
209+
{
210+
const entries = list.getEntriesByType('resource');
211+
assert.strictEqual(entries.length, 1);
212+
assert(entries[0] instanceof PerformanceResourceTiming);
213+
}
214+
{
215+
const entries = list.getEntriesByName('http://localhost:8080');
216+
assert.strictEqual(entries.length, 1);
217+
assert(entries[0] instanceof PerformanceResourceTiming);
218+
}
219+
obs.disconnect();
220+
}));
221+
obs.observe({ entryTypes: ['resource'] });
222+
223+
const timingInfo = createTimingInfo({ finalConnectionTimingInfo: {} });
224+
const customGlobal = {};
225+
const requestedUrl = 'http://localhost:8080';
226+
const cacheMode = 'local';
227+
const initiatorType = 'fetch';
228+
const resource = markResourceTiming(
229+
timingInfo,
230+
requestedUrl,
231+
initiatorType,
232+
customGlobal,
233+
cacheMode,
234+
);
235+
236+
assert(resource instanceof PerformanceEntry);
237+
assert(resource instanceof PerformanceResourceTiming);
238+
239+
clearResourceTimings();
240+
const entries = performance.getEntries();
241+
assert.strictEqual(entries.length, 0);
127242
}

0 commit comments

Comments
 (0)