mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
perf(core): allow checkNoChanges mode to be tree-shaken in production (#45936)
This commit guards all logic that exists for the `checkNoChanges` mode with `ngDevMode` checks such that the logic can be tree-shaken. PR Close #45936
This commit is contained in:
@@ -104,7 +104,7 @@ export abstract class ChangeDetectorRef {
|
||||
* Checks the change detector and its children, and throws if any changes are detected.
|
||||
*
|
||||
* Use in development mode to verify that running change detection doesn't introduce
|
||||
* other changes.
|
||||
* other changes. Calling it in production mode is a noop.
|
||||
*/
|
||||
abstract checkNoChanges(): void;
|
||||
|
||||
|
||||
@@ -37,7 +37,8 @@ import {getLView, getSelectedIndex, getTView, isInCheckNoChangesMode, setSelecte
|
||||
*/
|
||||
export function ɵɵadvance(delta: number): void {
|
||||
ngDevMode && assertGreaterThan(delta, 0, 'Can only advance forward');
|
||||
selectIndexInternal(getTView(), getLView(), getSelectedIndex() + delta, isInCheckNoChangesMode());
|
||||
selectIndexInternal(
|
||||
getTView(), getLView(), getSelectedIndex() + delta, !!ngDevMode && isInCheckNoChangesMode());
|
||||
}
|
||||
|
||||
export function selectIndexInternal(
|
||||
|
||||
@@ -360,7 +360,7 @@ export function refreshView<T>(
|
||||
enterView(lView);
|
||||
// Check no changes mode is a dev only mode used to verify that bindings have not changed
|
||||
// since they were assigned. We do not want to execute lifecycle hooks in that mode.
|
||||
const isInCheckNoChangesPass = isInCheckNoChangesMode();
|
||||
const isInCheckNoChangesPass = ngDevMode && isInCheckNoChangesMode();
|
||||
try {
|
||||
resetPreOrderHookFlags(lView);
|
||||
|
||||
@@ -481,10 +481,14 @@ export function refreshView<T>(
|
||||
export function renderComponentOrTemplate<T>(
|
||||
tView: TView, lView: LView, templateFn: ComponentTemplate<{}>|null, context: T) {
|
||||
const rendererFactory = lView[RENDERER_FACTORY];
|
||||
const normalExecutionPath = !isInCheckNoChangesMode();
|
||||
|
||||
// Check no changes mode is a dev only mode used to verify that bindings have not changed
|
||||
// since they were assigned. We do not want to invoke renderer factory functions in that mode
|
||||
// to avoid any possible side-effects.
|
||||
const checkNoChangesMode = !!ngDevMode && isInCheckNoChangesMode();
|
||||
const creationModeIsActive = isCreationMode(lView);
|
||||
try {
|
||||
if (normalExecutionPath && !creationModeIsActive && rendererFactory.begin) {
|
||||
if (!checkNoChangesMode && !creationModeIsActive && rendererFactory.begin) {
|
||||
rendererFactory.begin();
|
||||
}
|
||||
if (creationModeIsActive) {
|
||||
@@ -492,7 +496,7 @@ export function renderComponentOrTemplate<T>(
|
||||
}
|
||||
refreshView(tView, lView, templateFn, context);
|
||||
} finally {
|
||||
if (normalExecutionPath && !creationModeIsActive && rendererFactory.end) {
|
||||
if (!checkNoChangesMode && !creationModeIsActive && rendererFactory.end) {
|
||||
rendererFactory.end();
|
||||
}
|
||||
}
|
||||
@@ -507,7 +511,7 @@ function executeTemplate<T>(
|
||||
if (isUpdatePhase && lView.length > HEADER_OFFSET) {
|
||||
// When we're updating, inherently select 0 so we don't
|
||||
// have to generate that instruction for most update blocks.
|
||||
selectIndexInternal(tView, lView, HEADER_OFFSET, isInCheckNoChangesMode());
|
||||
selectIndexInternal(tView, lView, HEADER_OFFSET, !!ngDevMode && isInCheckNoChangesMode());
|
||||
}
|
||||
|
||||
const preHookType =
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import {InjectFlags} from '../di/interface/injector';
|
||||
import {assertDefined, assertEqual, assertGreaterThanOrEqual, assertLessThan, assertNotEqual} from '../util/assert';
|
||||
import {assertDefined, assertEqual, assertGreaterThanOrEqual, assertLessThan, assertNotEqual, throwError} from '../util/assert';
|
||||
|
||||
import {assertLViewOrUndefined, assertTNodeForLView, assertTNodeForTView} from './assert';
|
||||
import {DirectiveDef} from './interfaces/definition';
|
||||
@@ -172,24 +172,23 @@ interface InstructionState {
|
||||
* ```
|
||||
*/
|
||||
bindingsEnabled: boolean;
|
||||
|
||||
/**
|
||||
* In this mode, any changes in bindings will throw an ExpressionChangedAfterChecked error.
|
||||
*
|
||||
* Necessary to support ChangeDetectorRef.checkNoChanges().
|
||||
*
|
||||
* checkNoChanges Runs only in devmode=true and verifies that no unintended changes exist in
|
||||
* the change detector or its children.
|
||||
*/
|
||||
isInCheckNoChangesMode: boolean;
|
||||
}
|
||||
|
||||
const instructionState: InstructionState = {
|
||||
lFrame: createLFrame(null),
|
||||
bindingsEnabled: true,
|
||||
isInCheckNoChangesMode: false,
|
||||
};
|
||||
|
||||
/**
|
||||
* In this mode, any changes in bindings will throw an ExpressionChangedAfterChecked error.
|
||||
*
|
||||
* Necessary to support ChangeDetectorRef.checkNoChanges().
|
||||
*
|
||||
* The `checkNoChanges` function is invoked only in ngDevMode=true and verifies that no unintended
|
||||
* changes exist in the change detector or its children.
|
||||
*/
|
||||
let _isInCheckNoChangesMode = false;
|
||||
|
||||
/**
|
||||
* Returns true if the instruction state stack is empty.
|
||||
*
|
||||
@@ -336,12 +335,13 @@ export function getContextLView(): LView {
|
||||
}
|
||||
|
||||
export function isInCheckNoChangesMode(): boolean {
|
||||
// TODO(misko): remove this from the LView since it is ngDevMode=true mode only.
|
||||
return instructionState.isInCheckNoChangesMode;
|
||||
!ngDevMode && throwError('Must never be called in production mode');
|
||||
return _isInCheckNoChangesMode;
|
||||
}
|
||||
|
||||
export function setIsInCheckNoChangesMode(mode: boolean): void {
|
||||
instructionState.isInCheckNoChangesMode = mode;
|
||||
!ngDevMode && throwError('Must never be called in production mode');
|
||||
_isInCheckNoChangesMode = mode;
|
||||
}
|
||||
|
||||
// top level variables should not be exported for performance reasons (PERF_NOTES.md)
|
||||
|
||||
@@ -281,7 +281,9 @@ export class ViewRef<T> implements viewEngine_EmbeddedViewRef<T>, viewEngine_Int
|
||||
* introduce other changes.
|
||||
*/
|
||||
checkNoChanges(): void {
|
||||
checkNoChangesInternal(this._lView[TVIEW], this._lView, this.context);
|
||||
if (ngDevMode) {
|
||||
checkNoChangesInternal(this._lView[TVIEW], this._lView, this.context);
|
||||
}
|
||||
}
|
||||
|
||||
attachToViewContainerRef() {
|
||||
@@ -318,7 +320,9 @@ export class RootViewRef<T> extends ViewRef<T> {
|
||||
}
|
||||
|
||||
override checkNoChanges(): void {
|
||||
checkNoChangesInRootView(this._view);
|
||||
if (ngDevMode) {
|
||||
checkNoChangesInRootView(this._view);
|
||||
}
|
||||
}
|
||||
|
||||
override get context(): T {
|
||||
|
||||
@@ -716,12 +716,6 @@
|
||||
{
|
||||
"name": "detachMovedView"
|
||||
},
|
||||
{
|
||||
"name": "detectChangesInRootView"
|
||||
},
|
||||
{
|
||||
"name": "detectChangesInternal"
|
||||
},
|
||||
{
|
||||
"name": "diPublicInInjector"
|
||||
},
|
||||
@@ -998,9 +992,6 @@
|
||||
{
|
||||
"name": "isFunction"
|
||||
},
|
||||
{
|
||||
"name": "isInCheckNoChangesMode"
|
||||
},
|
||||
{
|
||||
"name": "isInlineTemplate"
|
||||
},
|
||||
@@ -1286,9 +1277,6 @@
|
||||
{
|
||||
"name": "setInputsFromAttrs"
|
||||
},
|
||||
{
|
||||
"name": "setIsInCheckNoChangesMode"
|
||||
},
|
||||
{
|
||||
"name": "setSelectedIndex"
|
||||
},
|
||||
@@ -1388,4 +1376,4 @@
|
||||
{
|
||||
"name": "ɵɵproperty"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
@@ -242,9 +242,6 @@
|
||||
{
|
||||
"name": "isCurrentTNodeParent"
|
||||
},
|
||||
{
|
||||
"name": "isInCheckNoChangesMode"
|
||||
},
|
||||
{
|
||||
"name": "isInlineTemplate"
|
||||
},
|
||||
|
||||
@@ -737,12 +737,6 @@
|
||||
{
|
||||
"name": "detachView"
|
||||
},
|
||||
{
|
||||
"name": "detectChangesInRootView"
|
||||
},
|
||||
{
|
||||
"name": "detectChangesInternal"
|
||||
},
|
||||
{
|
||||
"name": "diPublicInInjector"
|
||||
},
|
||||
@@ -1109,9 +1103,6 @@
|
||||
{
|
||||
"name": "isFunction"
|
||||
},
|
||||
{
|
||||
"name": "isInCheckNoChangesMode"
|
||||
},
|
||||
{
|
||||
"name": "isInlineTemplate"
|
||||
},
|
||||
@@ -1436,9 +1427,6 @@
|
||||
{
|
||||
"name": "setInputsFromAttrs"
|
||||
},
|
||||
{
|
||||
"name": "setIsInCheckNoChangesMode"
|
||||
},
|
||||
{
|
||||
"name": "setSelectedIndex"
|
||||
},
|
||||
|
||||
@@ -716,12 +716,6 @@
|
||||
{
|
||||
"name": "detachView"
|
||||
},
|
||||
{
|
||||
"name": "detectChangesInRootView"
|
||||
},
|
||||
{
|
||||
"name": "detectChangesInternal"
|
||||
},
|
||||
{
|
||||
"name": "diPublicInInjector"
|
||||
},
|
||||
@@ -1073,9 +1067,6 @@
|
||||
{
|
||||
"name": "isFunction"
|
||||
},
|
||||
{
|
||||
"name": "isInCheckNoChangesMode"
|
||||
},
|
||||
{
|
||||
"name": "isInlineTemplate"
|
||||
},
|
||||
@@ -1418,9 +1409,6 @@
|
||||
{
|
||||
"name": "setInputsFromAttrs"
|
||||
},
|
||||
{
|
||||
"name": "setIsInCheckNoChangesMode"
|
||||
},
|
||||
{
|
||||
"name": "setSelectedIndex"
|
||||
},
|
||||
@@ -1574,4 +1562,4 @@
|
||||
{
|
||||
"name": "ɵɵtext"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
@@ -173,9 +173,6 @@
|
||||
{
|
||||
"name": "invertObject"
|
||||
},
|
||||
{
|
||||
"name": "isInCheckNoChangesMode"
|
||||
},
|
||||
{
|
||||
"name": "isProceduralRenderer"
|
||||
},
|
||||
@@ -251,4 +248,4 @@
|
||||
{
|
||||
"name": "ɵɵdefineComponent"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
@@ -992,12 +992,6 @@
|
||||
{
|
||||
"name": "detachView"
|
||||
},
|
||||
{
|
||||
"name": "detectChangesInRootView"
|
||||
},
|
||||
{
|
||||
"name": "detectChangesInternal"
|
||||
},
|
||||
{
|
||||
"name": "diPublicInInjector"
|
||||
},
|
||||
@@ -1415,9 +1409,6 @@
|
||||
{
|
||||
"name": "isImmediateMatch"
|
||||
},
|
||||
{
|
||||
"name": "isInCheckNoChangesMode"
|
||||
},
|
||||
{
|
||||
"name": "isInlineTemplate"
|
||||
},
|
||||
@@ -1760,9 +1751,6 @@
|
||||
{
|
||||
"name": "setInputsFromAttrs"
|
||||
},
|
||||
{
|
||||
"name": "setIsInCheckNoChangesMode"
|
||||
},
|
||||
{
|
||||
"name": "setRouterState"
|
||||
},
|
||||
@@ -1967,4 +1955,4 @@
|
||||
{
|
||||
"name": "ɵɵtextInterpolate1"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
@@ -305,12 +305,6 @@
|
||||
{
|
||||
"name": "detachView"
|
||||
},
|
||||
{
|
||||
"name": "detectChangesInRootView"
|
||||
},
|
||||
{
|
||||
"name": "detectChangesInternal"
|
||||
},
|
||||
{
|
||||
"name": "diPublicInInjector"
|
||||
},
|
||||
@@ -548,9 +542,6 @@
|
||||
{
|
||||
"name": "isDirectiveHost"
|
||||
},
|
||||
{
|
||||
"name": "isInCheckNoChangesMode"
|
||||
},
|
||||
{
|
||||
"name": "isInlineTemplate"
|
||||
},
|
||||
@@ -746,9 +737,6 @@
|
||||
{
|
||||
"name": "setInputsFromAttrs"
|
||||
},
|
||||
{
|
||||
"name": "setIsInCheckNoChangesMode"
|
||||
},
|
||||
{
|
||||
"name": "setSelectedIndex"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user