node/lib/internal/perf/resource_timing.js
RafaelGSS 78c8d2a8c8 perf_hooks: add PerformanceResourceTiming
perf_hooks: create clearResourceTimings

perf_hooks: add resourcetiming test parallel

perf_hooks: add markResourceTiming

perf_hooks: fix observable when using resource

perf_hooks: fix observable when using resource

perf_hooks: add class comments

perf_hooks: add PerformanceResourceTiming

perf_hooks: create clearResourceTimings

perf_hooks: add resourcetiming test parallel

perf_hooks: add markResourceTiming

perf_hooks: fix observable when using resource

perf_hooks: fix observable when using resource

perf_hooks: add class comments

perf_hooks: add Resource Timing documentation

benchmark: measure resource timing module

perf_hooks: add check avoiding new PerformanceResourceTiming

perf_hooks: adjust doc

PR-URL: https://github.com/nodejs/node/pull/42725
Fixes: https://github.com/nodejs/undici/issues/952
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
2022-05-13 09:20:01 -03:00

180 lines
4.6 KiB
JavaScript

'use strict';
// https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming
const { InternalPerformanceEntry } = require('internal/perf/performance_entry');
const { SymbolToStringTag } = primordials;
const assert = require('internal/assert');
const { enqueue } = require('internal/perf/observe');
const { Symbol, ObjectSetPrototypeOf } = primordials;
const kCacheMode = Symbol('kCacheMode');
const kRequestedUrl = Symbol('kRequestedUrl');
const kTimingInfo = Symbol('kTimingInfo');
const kInitiatorType = Symbol('kInitiatorType');
const {
codes: {
ERR_ILLEGAL_CONSTRUCTOR,
}
} = require('internal/errors');
class InternalPerformanceResourceTiming extends InternalPerformanceEntry {
constructor(requestedUrl, initiatorType, timingInfo, cacheMode = '') {
super(requestedUrl, 'resource');
this[kInitiatorType] = initiatorType;
this[kRequestedUrl] = requestedUrl;
// https://fetch.spec.whatwg.org/#fetch-timing-info
// This class is using timingInfo assuming it's already validated.
// The spec doesn't say to validate it in the class construction.
this[kTimingInfo] = timingInfo;
this[kCacheMode] = cacheMode;
}
get [SymbolToStringTag]() {
return 'PerformanceResourceTiming';
}
get name() {
return this[kRequestedUrl];
}
get startTime() {
return this[kTimingInfo].startTime;
}
get duration() {
return this[kTimingInfo].endTime - this[kTimingInfo].startTime;
}
get workerStart() {
return this[kTimingInfo].finalServiceWorkerStartTime;
}
get redirectStart() {
return this[kTimingInfo].redirectStartTime;
}
get redirectEnd() {
return this[kTimingInfo].redirectEndTime;
}
get fetchStart() {
return this[kTimingInfo].postRedirectStartTime;
}
get domainLookupStart() {
return this[kTimingInfo].finalConnectionTimingInfo?.domainLookupStartTime;
}
get domainLookupEnd() {
return this[kTimingInfo].finalConnectionTimingInfo?.domainLookupEndTime;
}
get connectStart() {
return this[kTimingInfo].finalConnectionTimingInfo?.connectionStartTime;
}
get connectEnd() {
return this[kTimingInfo].finalConnectionTimingInfo?.connectionEndTime;
}
get secureConnectionStart() {
return this[kTimingInfo]
.finalConnectionTimingInfo?.secureConnectionStartTime;
}
get nextHopProtocol() {
return this[kTimingInfo]
.finalConnectionTimingInfo?.ALPNNegotiatedProtocol;
}
get requestStart() {
return this[kTimingInfo].finalNetworkRequestStartTime;
}
get responseStart() {
return this[kTimingInfo].finalNetworkResponseStartTime;
}
get responseEnd() {
return this[kTimingInfo].endTime;
}
get encodedBodySize() {
return this[kTimingInfo].encodedBodySize;
}
get decodedBodySize() {
return this[kTimingInfo].decodedBodySize;
}
get transferSize() {
if (this[kCacheMode] === 'local') return 0;
if (this[kCacheMode] === 'validated') return 300;
return this[kTimingInfo].encodedBodySize + 300;
}
toJSON() {
return {
name: this.name,
entryType: this.entryType,
startTime: this.startTime,
duration: this.duration,
initiatorType: this[kInitiatorType],
nextHopProtocol: this.nextHopProtocol,
workerStart: this.workerStart,
redirectStart: this.redirectStart,
redirectEnd: this.redirectEnd,
fetchStart: this.fetchStart,
domainLookupStart: this.domainLookupStart,
domainLookupEnd: this.domainLookupEnd,
connectStart: this.connectStart,
connectEnd: this.connectEnd,
secureConnectionStart: this.secureConnectionStart,
requestStart: this.requestStart,
responseStart: this.responseStart,
responseEnd: this.responseEnd,
transferSize: this.transferSize,
encodedBodySize: this.encodedBodySize,
decodedBodySize: this.decodedBodySize,
};
}
}
class PerformanceResourceTiming extends InternalPerformanceResourceTiming {
constructor() {
throw new ERR_ILLEGAL_CONSTRUCTOR();
}
}
// https://w3c.github.io/resource-timing/#dfn-mark-resource-timing
function markResourceTiming(
timingInfo,
requestedUrl,
initiatorType,
global,
cacheMode,
) {
// https://w3c.github.io/resource-timing/#dfn-setup-the-resource-timing-entry
assert(
cacheMode === '' || cacheMode === 'local',
'cache must be an empty string or \'local\'',
);
const resource = new InternalPerformanceResourceTiming(
requestedUrl,
initiatorType,
timingInfo,
cacheMode,
);
ObjectSetPrototypeOf(resource, PerformanceResourceTiming.prototype);
enqueue(resource);
return resource;
}
module.exports = {
PerformanceResourceTiming,
markResourceTiming,
};