Skip to content

Commit

Permalink
fix(explorer): debounce dirty notifications and ignore vendorChunk (r…
Browse files Browse the repository at this point in the history
…angle#264)

1. On scroll event we can very aggressively request updates. Although we have throttling logic, it still can be quite a heavy operation in the front end. Here we introduce 50ms throttling.
2. Do not produce `vendorChunk` in development (and production) modes.
  • Loading branch information
mgechev committed Apr 8, 2020
1 parent 2339318 commit 97d6b3d
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 17 deletions.
4 changes: 2 additions & 2 deletions angular.json
Expand Up @@ -22,6 +22,7 @@
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"vendorChunk": false,
"aot": true,
"assets": ["src/favicon.ico", "src/assets"],
"styles": [
Expand All @@ -45,7 +46,6 @@
"extractCss": true,
"namedChunks": false,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
Expand Down Expand Up @@ -133,6 +133,7 @@
"main": "projects/shell-chrome/src/main.ts",
"polyfills": "projects/shell-chrome/src/polyfills.ts",
"tsConfig": "projects/shell-chrome/tsconfig.app.json",
"vendorChunk": false,
"aot": true,
"assets": [
"projects/shell-chrome/src/favicon.ico",
Expand All @@ -158,7 +159,6 @@
"extractCss": true,
"namedChunks": false,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
Expand Down
18 changes: 7 additions & 11 deletions projects/ng-devtools-backend/src/lib/change-detection-tracker.ts
@@ -1,20 +1,14 @@
import { buildDirectiveForest, ComponentTreeNode } from './component-tree';
import { runOutsideAngular, patchTemplate } from './utils';
import { Subject } from 'rxjs';

let hookInitialized = false;
export const onChangeDetection$ = new Subject();

export const onChangeDetection = (callback: () => void): void => {
if (hookInitialized) {
return;
}
const forest = buildDirectiveForest();
listenAndNotifyOnUpdates(forest, callback);
hookInitialized = true;
};
const forest = buildDirectiveForest();

// We patch the component tView template function reference
// to detect when the change detection has completed and notify the client.
const listenAndNotifyOnUpdates = (roots: ComponentTreeNode[], callback: () => void): void => {
const listenAndNotifyOnUpdates = (roots: ComponentTreeNode[]): void => {
roots.forEach((root) => {
const { component } = root;
if (!component) {
Expand All @@ -23,8 +17,10 @@ const listenAndNotifyOnUpdates = (roots: ComponentTreeNode[], callback: () => vo
}
patchTemplate(component.instance, () => {
runOutsideAngular(() => {
setTimeout(callback, 0);
setTimeout(() => onChangeDetection$.next(), 0);
});
});
});
};

listenAndNotifyOnUpdates(forest);
Expand Up @@ -9,7 +9,7 @@ import {
ProfilerFrame,
ComponentExplorerViewQuery,
} from 'protocol';
import { onChangeDetection } from './change-detection-tracker';
import { onChangeDetection$ } from './change-detection-tracker';
import { ComponentTreeNode, getLatestComponentState, queryDirectiveForest, updateState } from './component-tree';
import { start as startProfiling, stop as stopProfiling } from './observer';
import { serializeDirectiveState } from './state-serializer/state-serializer';
Expand All @@ -18,6 +18,7 @@ import { setConsoleReference } from './selected-component';
import { unHighlight } from './highlighter';
import { getAngularVersion, appIsAngularInDevMode, appIsSupportedAngularVersion } from './angular-check';
import { observeDOM, getDirectiveId, getDirectiveForest, indexDirectiveForest } from './component-tree-identifiers';
import { debounceTime } from 'rxjs/operators';

export const subscribeToClientEvents = (messageBus: MessageBus<Events>): void => {
messageBus.on('shutdown', shutdownCallback(messageBus));
Expand All @@ -37,7 +38,11 @@ export const subscribeToClientEvents = (messageBus: MessageBus<Events>): void =>

if (appIsAngularInDevMode() && appIsSupportedAngularVersion()) {
setupInspector(messageBus);
onChangeDetection(() => messageBus.emit('componentTreeDirty'));
// Often websites have `scroll` event listener which triggers
// Angular's change detection. We don't want to constantly send
// update requests, instead we want to request an update at most
// every 50ms
onChangeDetection$.pipe(debounceTime(50)).subscribe(() => messageBus.emit('componentTreeDirty'));
}
};

Expand Down
Expand Up @@ -55,6 +55,8 @@ export class DirectiveExplorerComponent implements OnInit {

private _changeSize = new Subject<Event>();
private _clickedElement: IndexedNode | null = null;
private _refreshRetryTimeout: any = null;

parents: FlatNode[] | null = null;

@ViewChild(DirectiveForestComponent) directiveForest: DirectiveForestComponent;
Expand Down Expand Up @@ -114,8 +116,15 @@ export class DirectiveExplorerComponent implements OnInit {

refresh(): void {
const success = this._messageBus.emit('getLatestComponentExplorerView', [this._constructViewQuery()]);
if (!success) {
setTimeout(() => this.refresh(), 500);
// If the event was not throttled, we no longer need to retry.
if (success) {
clearTimeout(this._refreshRetryTimeout);
this._refreshRetryTimeout = null;
return;
}
// If the event was throttled and we haven't scheduled a retry yet.
if (!this._refreshRetryTimeout) {
this._refreshRetryTimeout = setTimeout(() => this.refresh(), 500);
}
}

Expand Down

0 comments on commit 97d6b3d

Please sign in to comment.