@@ -24,18 +24,22 @@ import { AsyncTask } from './zone-types';
2424import {
2525 OnPageInteractionStopwatch ,
2626 startOnPageInteraction ,
27- } from './on-page-interaction' ;
27+ } from './on-page-interaction-stop-watch ' ;
2828
2929// Allows us to monkey patch Zone prototype without TS compiler errors.
3030declare const Zone : ZoneType & { prototype : Zone } ;
3131
3232// Delay of 50 ms to reset currentEventTracingZone.
33- const RESET_TRACING_ZONE_DELAY = 50 ;
33+ export const RESET_TRACING_ZONE_DELAY = 50 ;
3434
3535export class InteractionTracker {
3636 // Allows to track several events triggered by the same user interaction in the right Zone.
3737 private currentEventTracingZone ?: Zone ;
3838
39+ // Used to reset the currentEventTracingZone when the interaction
40+ // finishes before it is reset automatically.
41+ private currentResetTracingZoneTimeout ?: number ;
42+
3943 // Map of interaction Ids to stopwatches.
4044 private readonly interactions : {
4145 [ index : string ] : OnPageInteractionStopwatch ;
@@ -46,23 +50,26 @@ export class InteractionTracker {
4650 [ index : string ] : number ;
4751 } = { } ;
4852
49- constructor ( ) {
53+ private static singletonInstance : InteractionTracker ;
54+
55+ private constructor ( ) {
5056 this . patchZoneRunTask ( ) ;
5157 this . patchZoneScheduleTask ( ) ;
5258 this . patchZoneCancelTask ( ) ;
5359 this . patchHistoryApi ( ) ;
5460 }
5561
62+ static startTracking ( ) : void {
63+ if ( ! this . singletonInstance ) this . singletonInstance = new this ( ) ;
64+ }
65+
5666 private patchZoneRunTask ( ) {
5767 const runTask = Zone . prototype . runTask ;
5868 Zone . prototype . runTask = (
5969 task : AsyncTask ,
6070 applyThis : unknown ,
6171 applyArgs : unknown
6272 ) => {
63- console . warn ( 'Running task' ) ;
64- console . log ( task ) ;
65-
6673 const interceptingElement = getTrackedElement ( task ) ;
6774 const interactionName = resolveInteractionName (
6875 interceptingElement ,
@@ -87,7 +94,6 @@ export class InteractionTracker {
8794 try {
8895 return runTask . call ( task . zone as { } , task , applyThis , applyArgs ) ;
8996 } finally {
90- console . log ( 'Run task finished.' ) ;
9197 if (
9298 interceptingElement ||
9399 ( shouldCountTask ( task ) && isTrackedTask ( task ) )
@@ -155,7 +161,7 @@ export class InteractionTracker {
155161 tracing . tracer . startRootSpan ( spanOptions , root => {
156162 // As startRootSpan creates the zone and Zone.current corresponds to the
157163 // new zone, we have to set the currentEventTracingZone with the Zone.current
158- // to capture the new zone, also, start the `OnPageInteraction` to capture the
164+ // to capture the new zone, also, start the `OnPageInteraction` to capture the
159165 // new root span.
160166 this . currentEventTracingZone = Zone . current ;
161167 this . interactions [ traceId ] = startOnPageInteraction ( {
@@ -170,14 +176,19 @@ export class InteractionTracker {
170176
171177 // Timeout to reset currentEventTracingZone to allow the creation of a new
172178 // zone for a new user interaction.
173- Zone . root . run ( ( ) =>
174- setTimeout (
175- ( ) => ( this . currentEventTracingZone = undefined ) ,
179+ Zone . root . run ( ( ) => {
180+ // Store the timeout in case the interaction finishes before
181+ // this callback runs.
182+ this . currentResetTracingZoneTimeout = window . setTimeout (
183+ ( ) => this . resetCurrentTracingZone ( ) ,
176184 RESET_TRACING_ZONE_DELAY
177- )
178- ) ;
179- console . log ( 'New zone:' ) ;
180- console . log ( this . currentEventTracingZone ) ;
185+ ) ;
186+ } ) ;
187+ }
188+
189+ private resetCurrentTracingZone ( ) {
190+ this . currentEventTracingZone = undefined ;
191+ this . currentResetTracingZoneTimeout = undefined ;
181192 }
182193
183194 /** Increments the count of outstanding tasks for a given interaction id. */
@@ -233,6 +244,14 @@ export class InteractionTracker {
233244 this . interactionCompletionTimeouts [ interactionId ] = setTimeout ( ( ) => {
234245 this . completeInteraction ( interactionId ) ;
235246 delete this . interactionCompletionTimeouts [ interactionId ] ;
247+ // In case the interaction finished beforeresetCurrentTracingZone is called,
248+ // this in order to allow the creating of a new interaction.
249+ if ( this . currentResetTracingZoneTimeout ) {
250+ Zone . root . run ( ( ) => {
251+ clearTimeout ( this . currentResetTracingZoneTimeout ) ;
252+ this . resetCurrentTracingZone ( ) ;
253+ } ) ;
254+ }
236255 } ) ;
237256 } ) ;
238257 }
@@ -375,10 +394,15 @@ function resolveInteractionName(
375394function shouldCountTask ( task : Task ) : boolean {
376395 if ( ! task . data ) return false ;
377396
378- // Don't count periodic tasks with a delay greater than 1 s.
379- if ( task . data . isPeriodic && ( task . data . delay && task . data . delay >= 1000 ) ) {
380- return false ;
381- }
397+ // Don't count periodic tasks like setInterval as they will be repeatedly
398+ // called. This will cause that the interaction never finishes, then would be
399+ // imposible to measure the stability of the interaction.
400+ // This case only applies for `setInterval` as we support `setTimeout`.
401+ // TODO: ideally OpenCensus Web can manage this kind of tasks, so for example
402+ // if a periodic task ends up doing some work in the future it will still
403+ // be associated with that same older tracing zone. This is something we have to
404+ // think of.
405+ if ( task . data . isPeriodic ) return false ;
382406
383407 // We're only interested in macroTasks and microTasks.
384408 return task . type === 'macroTask' || task . type === 'microTask' ;
0 commit comments