Skip to content

Commit

Permalink
Add interaction-tracking/subscriptions (#13426)
Browse files Browse the repository at this point in the history
* Removed enableInteractionTrackingObserver as a separate flag; only enableInteractionTracking is used now

* Added interaction-tracking/subscriptions bundle and split tests

* Added multi-subscriber support

* Moved subscriptions behind feature flag

* Fixed bug with wrap() parameters and added test

* Replaced wrap arrow function
  • Loading branch information
bvaughn authored Aug 17, 2018
1 parent 4b32f52 commit 0da5102
Show file tree
Hide file tree
Showing 17 changed files with 856 additions and 653 deletions.
1 change: 1 addition & 0 deletions packages/interaction-tracking/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"LICENSE",
"README.md",
"index.js",
"subscriptions.js",
"cjs/",
"umd/"
],
Expand Down
191 changes: 81 additions & 110 deletions packages/interaction-tracking/src/InteractionTracking.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@
* @flow
*/

import {
enableInteractionTracking,
enableInteractionTrackingObserver,
} from 'shared/ReactFeatureFlags';
import {enableInteractionTracking} from 'shared/ReactFeatureFlags';

export type Interaction = {|
__count: number,
Expand Down Expand Up @@ -71,18 +68,15 @@ let threadIDCounter: number = 0;
let interactionsRef: InteractionsRef = (null: any);

// Listener(s) to notify when interactions begin and end.
// Note that subscribers are only supported when enableInteractionTrackingObserver is enabled.
let subscriberRef: SubscriberRef = (null: any);

if (enableInteractionTracking) {
interactionsRef = {
current: new Set(),
};
if (enableInteractionTrackingObserver) {
subscriberRef = {
current: null,
};
}
subscriberRef = {
current: null,
};
}

// These values are exported for libraries with advanced use cases (i.e. React).
Expand Down Expand Up @@ -127,7 +121,7 @@ export function track(
}

const interaction: Interaction = {
__count: 0,
__count: 1,
id: interactionIDCounter++,
name,
timestamp,
Expand All @@ -142,53 +136,42 @@ export function track(
interactions.add(interaction);
interactionsRef.current = interactions;

if (enableInteractionTrackingObserver) {
// Update before calling callback in case it schedules follow-up work.
interaction.__count = 1;

let returnValue;
const subscriber = subscriberRef.current;
const subscriber = subscriberRef.current;
let returnValue;

try {
if (subscriber !== null) {
subscriber.onInteractionTracked(interaction);
}
} finally {
try {
if (subscriber !== null) {
subscriber.onInteractionTracked(interaction);
subscriber.onWorkStarted(interactions, threadID);
}
} finally {
try {
if (subscriber !== null) {
subscriber.onWorkStarted(interactions, threadID);
}
returnValue = callback();
} finally {
interactionsRef.current = prevInteractions;

try {
returnValue = callback();
if (subscriber !== null) {
subscriber.onWorkStopped(interactions, threadID);
}
} finally {
interactionsRef.current = prevInteractions;
interaction.__count--;

try {
if (subscriber !== null) {
subscriber.onWorkStopped(interactions, threadID);
}
} finally {
interaction.__count--;

// If no async work was scheduled for this interaction,
// Notify subscribers that it's completed.
if (subscriber !== null && interaction.__count === 0) {
subscriber.onInteractionScheduledWorkCompleted(interaction);
}
// If no async work was scheduled for this interaction,
// Notify subscribers that it's completed.
if (subscriber !== null && interaction.__count === 0) {
subscriber.onInteractionScheduledWorkCompleted(interaction);
}
}
}
}

return returnValue;
} else {
try {
return callback();
} finally {
interactionsRef.current = prevInteractions;
}
}

return returnValue;
}

export function wrap(
Expand All @@ -201,89 +184,77 @@ export function wrap(

const wrappedInteractions = interactionsRef.current;

if (enableInteractionTrackingObserver) {
const subscriber = subscriberRef.current;
if (subscriber !== null) {
subscriber.onWorkScheduled(wrappedInteractions, threadID);
}

// Update the pending async work count for the current interactions.
// Update after calling subscribers in case of error.
wrappedInteractions.forEach(interaction => {
interaction.__count++;
});
let subscriber = subscriberRef.current;
if (subscriber !== null) {
subscriber.onWorkScheduled(wrappedInteractions, threadID);
}

const wrapped = () => {
// Update the pending async work count for the current interactions.
// Update after calling subscribers in case of error.
wrappedInteractions.forEach(interaction => {
interaction.__count++;
});

function wrapped() {
const prevInteractions = interactionsRef.current;
interactionsRef.current = wrappedInteractions;

if (enableInteractionTrackingObserver) {
const subscriber = subscriberRef.current;
subscriber = subscriberRef.current;

try {
let returnValue;
try {
let returnValue;

try {
if (subscriber !== null) {
subscriber.onWorkStarted(wrappedInteractions, threadID);
}
} finally {
try {
returnValue = callback.apply(undefined, arguments);
} finally {
interactionsRef.current = prevInteractions;

if (subscriber !== null) {
subscriber.onWorkStopped(wrappedInteractions, threadID);
}
}
try {
if (subscriber !== null) {
subscriber.onWorkStarted(wrappedInteractions, threadID);
}

return returnValue;
} finally {
// Update pending async counts for all wrapped interactions.
// If this was the last scheduled async work for any of them,
// Mark them as completed.
wrappedInteractions.forEach(interaction => {
interaction.__count--;
try {
returnValue = callback.apply(undefined, arguments);
} finally {
interactionsRef.current = prevInteractions;

if (subscriber !== null && interaction.__count === 0) {
subscriber.onInteractionScheduledWorkCompleted(interaction);
if (subscriber !== null) {
subscriber.onWorkStopped(wrappedInteractions, threadID);
}
});
}
} else {
try {
return callback.apply(undefined, arguments);
} finally {
interactionsRef.current = prevInteractions;
}
}
}
};

if (enableInteractionTrackingObserver) {
wrapped.cancel = () => {
const subscriber = subscriberRef.current;

try {
if (subscriber !== null) {
subscriber.onWorkCanceled(wrappedInteractions, threadID);
return returnValue;
} finally {
// Update pending async counts for all wrapped interactions.
// If this was the last scheduled async work for any of them,
// Mark them as completed.
wrappedInteractions.forEach(interaction => {
interaction.__count--;

if (subscriber !== null && interaction.__count === 0) {
subscriber.onInteractionScheduledWorkCompleted(interaction);
}
} finally {
// Update pending async counts for all wrapped interactions.
// If this was the last scheduled async work for any of them,
// Mark them as completed.
wrappedInteractions.forEach(interaction => {
interaction.__count--;
});
}
}

if (subscriber && interaction.__count === 0) {
subscriber.onInteractionScheduledWorkCompleted(interaction);
}
});
wrapped.cancel = function cancel() {
subscriber = subscriberRef.current;

try {
if (subscriber !== null) {
subscriber.onWorkCanceled(wrappedInteractions, threadID);
}
};
}
} finally {
// Update pending async counts for all wrapped interactions.
// If this was the last scheduled async work for any of them,
// Mark them as completed.
wrappedInteractions.forEach(interaction => {
interaction.__count--;

if (subscriber && interaction.__count === 0) {
subscriber.onInteractionScheduledWorkCompleted(interaction);
}
});
}
};

return wrapped;
}
Loading

0 comments on commit 0da5102

Please sign in to comment.