Skip to content

Commit b728149

Browse files
committed
perf_hooks: add markResourceTiming
1 parent 8aebe6e commit b728149

3 files changed

Lines changed: 149 additions & 4 deletions

File tree

lib/internal/perf/performance.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ const {
1919

2020
const { now } = require('internal/perf/utils');
2121

22+
const { markResourceTiming } = require('internal/perf/resource_timing');
23+
2224
const {
2325
mark,
2426
measure,
@@ -164,6 +166,11 @@ ObjectDefineProperties(Performance.prototype, {
164166
enumerable: false,
165167
value: nodeTiming,
166168
},
169+
markResourceTiming: {
170+
configurable: true,
171+
enumerable: false,
172+
value: markResourceTiming,
173+
},
167174
now: {
168175
configurable: true,
169176
enumerable: false,

lib/internal/perf/resource_timing.js

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
const { InternalPerformanceEntry } = require('internal/perf/performance_entry');
55
const { SymbolToStringTag } = primordials;
66
const assert = require('assert')
7+
const { enqueue } = require('internal/perf/observe');
78

89
const kCacheMode = Symbol('kCacheMode');
910
const kRequestedUrl = Symbol('kRequestedUrl');
@@ -12,7 +13,7 @@ const kInitiatorType = Symbol('kInitiatorType');
1213

1314
class PerformanceResourceTiming extends InternalPerformanceEntry {
1415
constructor(requestedUrl, start, initiatorType, timingInfo, cacheMode = "") {
15-
super(requestedUrl, 'resource', start, duration);
16+
super(requestedUrl, 'resource', start);
1617
// https://w3c.github.io/resource-timing/#dfn-setup-the-resource-timing-entry
1718
assert.ok(cacheMode === "" || cacheMode === "local")
1819
this[kInitiatorType] = initiatorType
@@ -104,7 +105,6 @@ class PerformanceResourceTiming extends InternalPerformanceEntry {
104105
if (this[kCacheMode] === 'local') return 0;
105106
if (this[kCacheMode] === 'validated') return 300;
106107

107-
// TODO: it might return NaN
108108
return this[kTimingInfo].encodedBodySize + 300;
109109
}
110110

@@ -122,6 +122,35 @@ class PerformanceResourceTiming extends InternalPerformanceEntry {
122122
}
123123
}
124124

125+
// https://w3c.github.io/resource-timing/#dfn-mark-resource-timing
126+
function markResourceTiming(
127+
timingInfo,
128+
requestedUrl,
129+
initiatorType,
130+
global,
131+
cacheMode
132+
) {
133+
// TODO(rafaelgss): Probably must have some asserts here for:
134+
// - timingInfo
135+
// - requestedUrl
136+
// - initiatorType
137+
// - cacheMode
138+
139+
// 1. Create a PerformanceResourceTiming object entry in global's realm.
140+
// TODO(rafaelgss): why and how should I put `resource` into global object?
141+
const resource = new PerformanceResourceTiming(
142+
requestedUrl,
143+
// TODO(rafaelgss): not sure about that
144+
timingInfo.startTime,
145+
initiatorType,
146+
timingInfo,
147+
cacheMode
148+
);
149+
enqueue(resource);
150+
return resource;
151+
}
152+
125153
module.exports = {
126154
PerformanceResourceTiming,
155+
markResourceTiming,
127156
};
Lines changed: 111 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,127 @@
11
'use strict';
22

3+
const common = require('../common');
34
const assert = require('assert');
45
const {
56
PerformanceObserver,
67
PerformanceEntry,
78
PerformanceResourceTiming,
89
performance: {
9-
clearResourceTimings
10+
clearResourceTimings,
11+
markResourceTiming,
1012
},
1113
} = require('perf_hooks');
1214

1315
assert(PerformanceObserver);
1416
assert(PerformanceEntry);
1517
assert(PerformanceResourceTiming);
1618
assert(clearResourceTimings);
19+
assert(markResourceTiming);
1720

18-
// TODO:continue once `markResourceTiming` is done
21+
function createTimingInfo({
22+
startTime = 0,
23+
redirectStartTime = 0,
24+
redirectEndTime = 0,
25+
postRedirectStartTime = 0,
26+
finalServiceWorkerStartTime = 0,
27+
finalNetworkRequestStartTime = 0,
28+
finalNetworkResponseStartTime = 0,
29+
endTime = 0,
30+
encodedBodySize = 0,
31+
decodedBodySize = 0,
32+
finalConnectionTimingInfo = null
33+
}) {
34+
if (finalConnectionTimingInfo !== null) {
35+
finalConnectionTimingInfo.domainLookupStartTime =
36+
finalConnectionTimingInfo.domainLookupStartTime || 0
37+
finalConnectionTimingInfo.domainLookupEndTime =
38+
finalConnectionTimingInfo.domainLookupEndTime || 0
39+
finalConnectionTimingInfo.connectionStartTime =
40+
finalConnectionTimingInfo.connectionStartTime || 0
41+
finalConnectionTimingInfo.connectionEndTime =
42+
finalConnectionTimingInfo.connectionEndTime || 0
43+
finalConnectionTimingInfo.secureConnectionStartTime =
44+
finalConnectionTimingInfo.secureConnectionStartTime || 0
45+
finalConnectionTimingInfo.ALPNNegotiatedProtocol =
46+
finalConnectionTimingInfo.ALPNNegotiatedProtocol || []
47+
}
48+
return {
49+
startTime,
50+
redirectStartTime,
51+
redirectEndTime,
52+
postRedirectStartTime,
53+
finalServiceWorkerStartTime,
54+
finalNetworkRequestStartTime,
55+
finalNetworkResponseStartTime,
56+
endTime,
57+
encodedBodySize,
58+
decodedBodySize,
59+
finalConnectionTimingInfo,
60+
}
61+
}
62+
63+
{
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'] });
80+
81+
const timingInfo = createTimingInfo({ finalConnectionTimingInfo: {} });
82+
const customGlobal = {};
83+
const requestedUrl = 'http://localhost:8080';
84+
const cacheMode = 'local';
85+
const initiatorType = 'fetch';
86+
const resource = markResourceTiming(
87+
timingInfo,
88+
requestedUrl,
89+
initiatorType,
90+
customGlobal,
91+
cacheMode,
92+
);
93+
94+
assert(resource instanceof PerformanceEntry);
95+
assert(resource instanceof PerformanceResourceTiming);
96+
97+
assert.strictEqual(resource.entryType, 'resource');
98+
assert.strictEqual(resource.name, requestedUrl);
99+
assert.ok(typeof resource.cacheMode === 'undefined', 'cacheMode does not have a getter');
100+
assert.strictEqual(resource.startTime, timingInfo.startTime);
101+
assert.strictEqual(resource.duration, 0);
102+
assert.strictEqual(resource.workerStart, 0);
103+
assert.strictEqual(resource.redirectStart, 0);
104+
assert.strictEqual(resource.redirectEnd, 0);
105+
assert.strictEqual(resource.fetchStart, 0);
106+
assert.strictEqual(resource.domainLookupStart, 0);
107+
assert.strictEqual(resource.domainLookupEnd, 0);
108+
assert.strictEqual(resource.connectStart, 0);
109+
assert.strictEqual(resource.connectEnd, 0);
110+
assert.strictEqual(resource.secureConnectionStart, 0);
111+
assert.deepEqual(resource.nextHopProtocol, []);
112+
assert.strictEqual(resource.requestStart, 0);
113+
assert.strictEqual(resource.responseStart, 0);
114+
assert.strictEqual(resource.responseEnd, 0);
115+
assert.strictEqual(resource.encodedBodySize, 0);
116+
assert.strictEqual(resource.decodedBodySize, 0);
117+
assert.strictEqual(resource.transferSize, 0);
118+
assert.deepEqual(resource.toJSON(), {
119+
initiatorType,
120+
requestedUrl,
121+
cacheMode,
122+
name: requestedUrl,
123+
entryType: 'resource',
124+
startTime: timingInfo.startTime,
125+
duration: 0
126+
});
127+
}

0 commit comments

Comments
 (0)