mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(core): avoid leaking view data in animations
The animations code currently tracks which views have running leave animations by adding them to a `Set`. This can leak memory if we don't clean something up on time. These changes switch to tracking the views by their ID which doesn't risk retaining the view. Fixes #66255.
This commit is contained in:
committed by
Kirill Cherkashin
parent
a0dfa5fa86
commit
80b0fbba1f
@@ -147,4 +147,5 @@ function determineLongestAnimationFromElementAnimations(
|
||||
}
|
||||
}
|
||||
|
||||
export const allLeavingAnimations = new Set<LView>();
|
||||
/** Tracks the IDs of LViews with leaving animations. */
|
||||
export const allLeavingAnimations = new Set<number>();
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
MAX_ANIMATION_TIMEOUT,
|
||||
} from '../../animation/interfaces';
|
||||
import {getLView, getCurrentTNode} from '../state';
|
||||
import {RENDERER, INJECTOR, CONTEXT, LView} from '../interfaces/view';
|
||||
import {RENDERER, INJECTOR, CONTEXT, LView, ID} from '../interfaces/view';
|
||||
import {getNativeByTNode} from '../util/view_utils';
|
||||
import {performanceMarkFeature} from '../../util/performance';
|
||||
import {Renderer} from '../interfaces/renderer';
|
||||
@@ -277,7 +277,7 @@ function runLeaveAnimations(
|
||||
|
||||
const renderer = lView[RENDERER];
|
||||
const ngZone = lView[INJECTOR].get(NgZone);
|
||||
allLeavingAnimations.add(lView);
|
||||
allLeavingAnimations.add(lView[ID]);
|
||||
(getLViewLeaveAnimations(lView).get(tNode.index)!.resolvers ??= []).push(resolve);
|
||||
|
||||
const activeClasses = getClassListFromValue(value);
|
||||
@@ -389,7 +389,7 @@ export function ɵɵanimateLeaveListener(value: AnimationFunction): typeof ɵɵa
|
||||
const tNode = getCurrentTNode()!;
|
||||
cancelLeavingNodes(tNode, lView);
|
||||
|
||||
allLeavingAnimations.add(lView);
|
||||
allLeavingAnimations.add(lView[ID]);
|
||||
|
||||
addAnimationToLView(getLViewLeaveAnimations(lView), tNode, () =>
|
||||
runLeaveAnimationFunction(lView, tNode, value),
|
||||
|
||||
@@ -28,6 +28,7 @@ import {
|
||||
DECLARATION_COMPONENT_VIEW,
|
||||
HEADER_OFFSET,
|
||||
HYDRATION,
|
||||
ID,
|
||||
INJECTOR,
|
||||
LView,
|
||||
TVIEW,
|
||||
@@ -578,7 +579,7 @@ function clearDetachAnimationList(lContainer: LContainer, index: number): void {
|
||||
if (lContainer.length <= CONTAINER_HEADER_OFFSET) return;
|
||||
|
||||
const indexInContainer = CONTAINER_HEADER_OFFSET + index;
|
||||
const viewToDetach = lContainer[indexInContainer];
|
||||
const viewToDetach = lContainer[indexInContainer] as LView;
|
||||
const animations = viewToDetach
|
||||
? (viewToDetach[ANIMATIONS] as AnimationLViewData | undefined)
|
||||
: undefined;
|
||||
@@ -590,7 +591,7 @@ function clearDetachAnimationList(lContainer: LContainer, index: number): void {
|
||||
) {
|
||||
const injector = viewToDetach[INJECTOR];
|
||||
removeFromAnimationQueue(injector, animations);
|
||||
allLeavingAnimations.delete(viewToDetach);
|
||||
allLeavingAnimations.delete(viewToDetach[ID]);
|
||||
animations.detachedLeaveAnimationFns = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +76,7 @@ import {
|
||||
TView,
|
||||
TViewType,
|
||||
INJECTOR,
|
||||
ID,
|
||||
} from './interfaces/view';
|
||||
import {assertTNodeType} from './node_assert';
|
||||
import {profiler} from './profiler';
|
||||
@@ -387,7 +388,7 @@ function runLeaveAnimationsWithCallback(
|
||||
if (animations == null || animations.leave == undefined || !animations.leave.has(tNode.index))
|
||||
return callback(false);
|
||||
|
||||
if (lView) allLeavingAnimations.add(lView);
|
||||
if (lView) allLeavingAnimations.add(lView[ID]);
|
||||
|
||||
addToAnimationQueue(
|
||||
injector,
|
||||
@@ -410,7 +411,7 @@ function runLeaveAnimationsWithCallback(
|
||||
animations.running = Promise.allSettled(runningAnimations);
|
||||
runAfterLeaveAnimations(lView!, callback);
|
||||
} else {
|
||||
if (lView) allLeavingAnimations.delete(lView);
|
||||
if (lView) allLeavingAnimations.delete(lView[ID]);
|
||||
callback(false);
|
||||
}
|
||||
},
|
||||
@@ -423,7 +424,7 @@ function runAfterLeaveAnimations(lView: LView, callback: Function) {
|
||||
if (runningAnimations) {
|
||||
runningAnimations.then(() => {
|
||||
lView[ANIMATIONS]!.running = undefined;
|
||||
allLeavingAnimations.delete(lView);
|
||||
allLeavingAnimations.delete(lView[ID]);
|
||||
callback(true);
|
||||
});
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user