Browse Source

Fix: Improve performance of ImageLoadObserver using capturing phase events.

It also simplified the code a bit.
Marek Lewandowski 6 years ago
parent
commit
f27a5ffea2
1 changed files with 7 additions and 62 deletions
  1. 7 62
      packages/ckeditor5-image/src/image/imageloadobserver.js

+ 7 - 62
packages/ckeditor5-image/src/image/imageloadobserver.js

@@ -20,65 +20,18 @@ import Observer from '@ckeditor/ckeditor5-engine/src/view/observer/observer';
  * @extends module:engine/view/observer/observer~Observer
  */
 export default class ImageLoadObserver extends Observer {
-	constructor( view ) {
-		super( view );
-
-		/**
-		 * List of img DOM elements that are observed by this observer.
-		 *
-		 * @private
-		 * @type {Set.<HTMLElement>}
-		 */
-		this._observedElements = new Set();
-	}
-
 	/**
 	 * @inheritDoc
 	 */
-	observe( domRoot, name ) {
-		const viewRoot = this.document.getRoot( name );
-
-		// When there is a change in one of the view element
-		// we need to check if there are any new `<img/>` elements to observe.
-		viewRoot.on( 'change:children', ( evt, node ) => {
-			// Wait for the render to be sure that `<img/>` elements are rendered in the DOM root.
-			this.view.once( 'render', () => this._updateObservedElements( domRoot, node ) );
-		} );
-	}
-
-	/**
-	 * Updates the list of observed `<img/>` elements.
-	 *
-	 * @private
-	 * @param {HTMLElement} domRoot DOM root element.
-	 * @param {module:engine/view/element~Element} viewNode View element where children have changed.
-	 */
-	_updateObservedElements( domRoot, viewNode ) {
-		if ( !viewNode.is( 'element' ) || viewNode.is( 'attributeElement' ) ) {
-			return;
-		}
-
-		const domNode = this.view.domConverter.mapViewToDom( viewNode );
+	observe( domRoot ) {
+		this.listenTo( domRoot, 'load', ( event, domEvent ) => {
+			const domElement = domEvent.path[ 0 ];
 
-		// If there is no `domNode` it means that it was removed from the DOM in the meanwhile.
-		if ( !domNode ) {
-			return;
-		}
-
-		for ( const domElement of domNode.querySelectorAll( 'img' ) ) {
-			if ( !this._observedElements.has( domElement ) ) {
-				this.listenTo( domElement, 'load', ( evt, domEvt ) => this._fireEvents( domEvt ) );
-				this._observedElements.add( domElement );
-			}
-		}
-
-		// Clean up the list of observed elements from elements that has been removed from the root.
-		for ( const domElement of this._observedElements ) {
-			if ( !domRoot.contains( domElement ) ) {
-				this.stopListening( domElement );
-				this._observedElements.delete( domElement );
+			if ( domElement.tagName == 'IMG' ) {
+				this._fireEvents( domEvent );
 			}
-		}
+			// Use capture phase for better performance (#4504).
+		}, { useCapture: true } );
 	}
 
 	/**
@@ -95,14 +48,6 @@ export default class ImageLoadObserver extends Observer {
 			this.document.fire( 'imageLoaded', domEvent );
 		}
 	}
-
-	/**
-	 * @inheritDoc
-	 */
-	destroy() {
-		this._observedElements.clear();
-		super.destroy();
-	}
 }
 
 /**