Browse Source

LoadingManager: Lazily instantiate abort controller. (#32120)

* Lazily instantiate `AbortController` in `LoadingManager`

* Removed abort controller nullish check

* Add basic `LoadingManager` abort controller unit tests

* Added TODO to revert `abortController` logic

* Mark `_abortController` as private with JSDoc
Ben 3 months ago
parent
commit
e6084f9459
2 changed files with 75 additions and 3 deletions
  1. 25 3
      src/loaders/LoadingManager.js
  2. 50 0
      test/unit/src/loaders/LoadingManager.tests.js

+ 25 - 3
src/loaders/LoadingManager.js

@@ -72,9 +72,10 @@ class LoadingManager {
 		/**
 		 * Used for aborting ongoing requests in loaders using this manager.
 		 *
-		 * @type {AbortController}
+		 * @private
+		 * @type {AbortController | null}
 		 */
-		this.abortController = new AbortController();
+		this._abortController = null;
 
 		/**
 		 * This should be called by any loader using the manager when the loader
@@ -285,8 +286,9 @@ class LoadingManager {
 		 */
 		this.abort = function () {
 
+
 			this.abortController.abort();
-			this.abortController = new AbortController();
+			this._abortController = null;
 
 			return this;
 
@@ -294,6 +296,26 @@ class LoadingManager {
 
 	}
 
+	// TODO: Revert this back to a single member variable once this issue has been fixed
+	// https://github.com/cloudflare/workerd/issues/3657
+
+	/**
+	 * Used for aborting ongoing requests in loaders using this manager.
+	 *
+	 * @type {AbortController}
+	 */
+	get abortController() {
+
+		if ( ! this._abortController ) {
+
+			this._abortController = new AbortController();
+
+		}
+
+		return this._abortController;
+
+	}
+
 }
 
 /**

+ 50 - 0
test/unit/src/loaders/LoadingManager.tests.js

@@ -121,6 +121,56 @@ export default QUnit.module( 'Loaders', () => {
 
 		} );
 
+		QUnit.test( 'abortController - lazy instantiation', ( assert ) => {
+
+			const loadingManager = new LoadingManager();
+
+			assert.equal( loadingManager._abortController, null, '_abortController is initially null.' );
+
+			const controller = loadingManager.abortController;
+
+			assert.ok( controller instanceof AbortController, 'abortController returns an AbortController instance.' );
+			assert.equal( loadingManager._abortController, controller, '_abortController is set after first access.' );
+
+			const controller2 = loadingManager.abortController;
+			assert.equal( controller, controller2, 'Subsequent accesses return the same AbortController instance.' );
+
+		} );
+
+		QUnit.test( 'abort() - aborts controller and resets', ( assert ) => {
+
+			const loadingManager = new LoadingManager();
+
+			const controller = loadingManager.abortController;
+
+			assert.ok( ! controller.signal.aborted, 'Controller signal is not aborted initially.' );
+
+			loadingManager.abort();
+
+			assert.ok( controller.signal.aborted, 'Controller signal is aborted after calling abort().' );
+			assert.equal( loadingManager._abortController, null, '_abortController is reset to null after abort().' );
+
+		} );
+
+		QUnit.test( 'abortController - recreation after abort', ( assert ) => {
+
+			const loadingManager = new LoadingManager();
+
+			const controller1 = loadingManager.abortController;
+
+			loadingManager.abort();
+
+			assert.ok( controller1.signal.aborted, 'First controller is aborted.' );
+			assert.equal( loadingManager._abortController, null, '_abortController is null after abort.' );
+
+			const controller2 = loadingManager.abortController;
+
+			assert.ok( controller2 instanceof AbortController, 'New AbortController is created.' );
+			assert.notEqual( controller1, controller2, 'New controller is a different instance from the aborted one.' );
+			assert.ok( ! controller2.signal.aborted, 'New controller signal is not aborted.' );
+
+		} );
+
 	} );
 
 } );

粤ICP备19079148号