Skip to content

Commit 7f1c557

Browse files
arturovtAndrewKushnir
authored andcommitted
fix(common): remove load on image once it fails to load (#52990)
This commit adds an `error` listener to image elements and removes both `load` and `error` listeners once the image loads or fails to load. The `load` listener would never have been removed if the image failed to load. PR Close #52990
1 parent fafcb0d commit 7f1c557

File tree

1 file changed

+21
-4
lines changed

1 file changed

+21
-4
lines changed

packages/common/src/directives/ng_optimized_image/ng_optimized_image.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -746,8 +746,9 @@ function assertGreaterThanZero(dir: NgOptimizedImage, inputValue: unknown, input
746746
*/
747747
function assertNoImageDistortion(
748748
dir: NgOptimizedImage, img: HTMLImageElement, renderer: Renderer2) {
749-
const removeListenerFn = renderer.listen(img, 'load', () => {
750-
removeListenerFn();
749+
const removeLoadListenerFn = renderer.listen(img, 'load', () => {
750+
removeLoadListenerFn();
751+
removeErrorListenerFn();
751752
const computedStyle = window.getComputedStyle(img);
752753
let renderedWidth = parseFloat(computedStyle.getPropertyValue('width'));
753754
let renderedHeight = parseFloat(computedStyle.getPropertyValue('height'));
@@ -828,6 +829,15 @@ function assertNoImageDistortion(
828829
}
829830
}
830831
});
832+
833+
// We only listen to the `error` event to remove the `load` event listener because it will not be
834+
// fired if the image fails to load. This is done to prevent memory leaks in development mode
835+
// because image elements aren't garbage-collected properly. It happens because zone.js stores the
836+
// event listener directly on the element and closures capture `dir`.
837+
const removeErrorListenerFn = renderer.listen(img, 'error', () => {
838+
removeLoadListenerFn();
839+
removeErrorListenerFn();
840+
});
831841
}
832842

833843
/**
@@ -870,8 +880,9 @@ function assertEmptyWidthAndHeight(dir: NgOptimizedImage) {
870880
*/
871881
function assertNonZeroRenderedHeight(
872882
dir: NgOptimizedImage, img: HTMLImageElement, renderer: Renderer2) {
873-
const removeListenerFn = renderer.listen(img, 'load', () => {
874-
removeListenerFn();
883+
const removeLoadListenerFn = renderer.listen(img, 'load', () => {
884+
removeLoadListenerFn();
885+
removeErrorListenerFn();
875886
const renderedHeight = img.clientHeight;
876887
if (dir.fill && renderedHeight === 0) {
877888
console.warn(formatRuntimeError(
@@ -883,6 +894,12 @@ function assertNonZeroRenderedHeight(
883894
`property defined and the height of the element is not zero.`));
884895
}
885896
});
897+
898+
// See comments in the `assertNoImageDistortion`.
899+
const removeErrorListenerFn = renderer.listen(img, 'error', () => {
900+
removeLoadListenerFn();
901+
removeErrorListenerFn();
902+
});
886903
}
887904

888905
/**

0 commit comments

Comments
 (0)