| '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 initiatorType() { |
| return this[kInitiatorType]; |
| } |
| |
| 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, |
| }; |