1616
1717import { Span } from '@opencensus/web-core' ;
1818import { XhrPerformanceResourceTiming } from './zone-types' ;
19+ import { alreadyAssignedPerfEntries } from './xhr-interceptor' ;
1920
2021/**
2122 * Get Browser's performance resource timing data associated to a XHR.
@@ -32,24 +33,29 @@ export function getXhrPerfomanceData(
3233 xhrUrl : string ,
3334 span : Span
3435) : XhrPerformanceResourceTiming | undefined {
35- const filteredPerfEntries = getPerfResourceEntries ( xhrUrl , span ) ;
36- const possibleEntries = getPossiblePerfResourceEntries ( filteredPerfEntries ) ;
36+ const filteredSortedPerfEntries = getPerfSortedResourceEntries ( xhrUrl , span ) ;
37+ const possibleEntries = getPossiblePerfResourceEntries (
38+ filteredSortedPerfEntries
39+ ) ;
3740 const bestEntry = getBestPerfResourceTiming ( possibleEntries , span ) ;
3841 return bestEntry ;
3942}
4043
4144/**
4245 * First step for the algorithm. Filter the Performance Resource Timings by the
4346 * name (it should match the XHR URL), additionally, the start/end timings of
44- * every performance entry should fit within the span start/end timings.
47+ * every performance entry should fit within the span start/end timings. Also,
48+ * the entry should be already assigned to a span.
4549 * These filtered performance resource entries are considered as possible
4650 * entries associated to the xhr.
4751 * Those are possible because there might be more than two entries that pass the
4852 * filter.
53+ * Additionally, the returned array is sorted by the entries' `startTime` as
54+ * getEntriesByType() already does it.
4955 * @param xhrUrl
5056 * @param span
5157 */
52- export function getPerfResourceEntries (
58+ export function getPerfSortedResourceEntries (
5359 xhrUrl : string ,
5460 span : Span
5561) : PerformanceResourceTiming [ ] {
@@ -70,42 +76,36 @@ export function getPerfResourceEntries(
7076 * 'paired' with any other entry.
7177 * Thus, for this step traverse the array of resource entries and for every
7278 * entry check if it is a possible performance resource entry.
73- * @param perfEntries
79+ * @param filteredSortedPerfEntries Sorted array of Performance Resource
80+ * Entries. This is sorted by the entries' `startTime`.
7481 */
7582export function getPossiblePerfResourceEntries (
76- perfEntries : PerformanceResourceTiming [ ]
83+ filteredSortedPerfEntries : PerformanceResourceTiming [ ]
7784) : XhrPerformanceResourceTiming [ ] {
7885 const possiblePerfEntries = new Array < XhrPerformanceResourceTiming > ( ) ;
79- const pairedEntries = new Set < PerformanceResourceTiming > ( ) ;
80- let entryI : PerformanceResourceTiming ;
81- let entryJ : PerformanceResourceTiming ;
8286 // As this part of the algorithm traverses the array twice, although,
8387 // this array is not large as the performance resource entries buffer is
8488 // cleared when there are no more running XHRs.
85- for ( let i = 0 ; i < perfEntries . length ; i ++ ) {
86- entryI = perfEntries [ i ] ;
87- // Compare every performance entry with its consecutive perfomance entries.
88- // That way to avoid comparing twice the entries.
89- for ( let j = i + 1 ; j < perfEntries . length ; j ++ ) {
90- entryJ = perfEntries [ j ] ;
91- if ( ! overlappingPerfResourceTimings ( entryI , entryJ ) ) {
89+ for ( let i = 0 ; i < filteredSortedPerfEntries . length ; i ++ ) {
90+ const entryI = filteredSortedPerfEntries [ i ] ;
91+ // Consider the current entry as a possible entry without cors preflight
92+ // request. This is valid as this entry might be better than other possible
93+ // entries.
94+ possiblePerfEntries . push ( { mainRequest : entryI } ) ;
95+ // Compare every performance entry with the perfomance entries in front of
96+ // it. This is possible as the entries are sorted by the startTime. That
97+ // way we to avoid comparing twice the entries and taking the wrong order.
98+ for ( let j = i + 1 ; j < filteredSortedPerfEntries . length ; j ++ ) {
99+ const entryJ = filteredSortedPerfEntries [ j ] ;
100+ if ( ! isPossibleCorsPair ( entryI , entryJ ) ) {
92101 // As the entries are not overlapping, that means those timings
93102 // are possible perfomance timings related to the XHR.
94103 possiblePerfEntries . push ( {
95104 corsPreFlightRequest : entryI ,
96105 mainRequest : entryJ ,
97106 } ) ;
98- pairedEntries . add ( entryI ) ;
99- pairedEntries . add ( entryJ ) ;
100107 }
101108 }
102- // If the entry couldn't be paired with any other resource timing,
103- // add it as a possible resource timing without cors preflight data.
104- // This is possible because this entry might be better than the other
105- // possible entries.
106- if ( ! pairedEntries . has ( entryI ) ) {
107- possiblePerfEntries . push ( { mainRequest : entryI } ) ;
108- }
109109 }
110110 return possiblePerfEntries ;
111111}
@@ -122,20 +122,16 @@ function getBestPerfResourceTiming(
122122 let minimumGapToSpan = Number . MAX_VALUE ;
123123 let bestPerfEntry : XhrPerformanceResourceTiming | undefined = undefined ;
124124 for ( const perfEntry of perfEntries ) {
125- let gapToSpan = Math . abs (
126- perfEntry . mainRequest . responseEnd - span . endPerfTime
127- ) ;
128125 // If the current entry has cors preflight data use its `startTime` to
129126 // calculate the gap to the span.
130- if ( perfEntry . corsPreFlightRequest ) {
131- gapToSpan += Math . abs (
132- perfEntry . corsPreFlightRequest . startTime - span . startPerfTime
133- ) ;
134- } else {
135- gapToSpan += Math . abs (
136- perfEntry . mainRequest . startTime - span . startPerfTime
137- ) ;
138- }
127+ const perfEntryStartTime = perfEntry . corsPreFlightRequest
128+ ? perfEntry . corsPreFlightRequest . startTime
129+ : perfEntry . mainRequest . startTime ;
130+ const gapToSpan =
131+ span . endPerfTime -
132+ perfEntry . mainRequest . responseEnd +
133+ ( perfEntryStartTime - span . startPerfTime ) ;
134+
139135 // If there is a new minimum gap to the span, update the minimum and pick
140136 // the current performance entry as the best at this point.
141137 if ( gapToSpan < minimumGapToSpan ) {
@@ -152,13 +148,14 @@ function isPerfEntryPartOfXhr(
152148 span : Span
153149) : boolean {
154150 return (
151+ ! alreadyAssignedPerfEntries . has ( entry ) &&
155152 entry . name === xhrUrl &&
156153 entry . startTime >= span . startPerfTime &&
157154 entry . responseEnd <= span . endPerfTime
158155 ) ;
159156}
160157
161- function overlappingPerfResourceTimings (
158+ function isPossibleCorsPair (
162159 entry1 : PerformanceResourceTiming ,
163160 entry2 : PerformanceResourceTiming
164161) : boolean {
0 commit comments