diff --git a/src/loaders/FileLoader.js b/src/loaders/FileLoader.js index 97061a61ea000d..886ae3d335e9e9 100644 --- a/src/loaders/FileLoader.js +++ b/src/loaders/FileLoader.js @@ -55,6 +55,14 @@ class FileLoader extends Loader { */ this.responseType = ''; + /** + * Used for aborting requests. + * + * @private + * @type {AbortController} + */ + this._abortController = new AbortController(); + } /** @@ -121,7 +129,7 @@ class FileLoader extends Loader { const req = new Request( url, { headers: new Headers( this.requestHeader ), credentials: this.withCredentials ? 'include' : 'same-origin', - // An abort controller could be added within a future PR + signal: ( typeof AbortSignal.any === 'function' ) ? AbortSignal.any( [ this._abortController.signal, this.manager.abortController.signal ] ) : this._abortController.signal } ); // record states ( avoid data race ) @@ -338,6 +346,20 @@ class FileLoader extends Loader { } + /** + * Aborts ongoing fetch requests. + * + * @return {FileLoader} A reference to this instance. + */ + abort() { + + this._abortController.abort(); + this._abortController = new AbortController(); + + return this; + + } + } diff --git a/src/loaders/ImageBitmapLoader.js b/src/loaders/ImageBitmapLoader.js index a8cca17f8bdbf1..8151df27d4a29d 100644 --- a/src/loaders/ImageBitmapLoader.js +++ b/src/loaders/ImageBitmapLoader.js @@ -66,6 +66,14 @@ class ImageBitmapLoader extends Loader { */ this.options = { premultiplyAlpha: 'none' }; + /** + * Used for aborting requests. + * + * @private + * @type {AbortController} + */ + this._abortController = new AbortController(); + } /** @@ -154,6 +162,7 @@ class ImageBitmapLoader extends Loader { const fetchOptions = {}; fetchOptions.credentials = ( this.crossOrigin === 'anonymous' ) ? 'same-origin' : 'include'; fetchOptions.headers = this.requestHeader; + fetchOptions.signal = ( typeof AbortSignal.any === 'function' ) ? AbortSignal.any( [ this._abortController.signal, this.manager.abortController.signal ] ) : this._abortController.signal; const promise = fetch( url, fetchOptions ).then( function ( res ) { @@ -191,6 +200,20 @@ class ImageBitmapLoader extends Loader { } + /** + * Aborts ongoing fetch requests. + * + * @return {ImageBitmapLoader} A reference to this instance. + */ + abort() { + + this._abortController.abort(); + this._abortController = new AbortController(); + + return this; + + } + } export { ImageBitmapLoader }; diff --git a/src/loaders/Loader.js b/src/loaders/Loader.js index ecd3bdcf2351fb..c18ae7c83a83c3 100644 --- a/src/loaders/Loader.js +++ b/src/loaders/Loader.js @@ -67,6 +67,7 @@ class Loader { * This method needs to be implemented by all concrete loaders. It holds the * logic for loading assets from the backend. * + * @abstract * @param {string} url - The path/URL of the file to be loaded. * @param {Function} onLoad - Executed when the loading process has been finished. * @param {onProgressCallback} [onProgress] - Executed while the loading is in progress. @@ -97,6 +98,7 @@ class Loader { * This method needs to be implemented by all concrete loaders. It holds the * logic for parsing the asset into three.js entities. * + * @abstract * @param {any} data - The data to parse. */ parse( /* data */ ) {} @@ -171,6 +173,18 @@ class Loader { } + /** + * This method can be implemented in loaders for aborting ongoing requests. + * + * @abstract + * @return {Loader} A reference to this instance. + */ + abort() { + + return this; + + } + } /** diff --git a/src/loaders/LoadingManager.js b/src/loaders/LoadingManager.js index bae742a457c878..69339f44ff2ed0 100644 --- a/src/loaders/LoadingManager.js +++ b/src/loaders/LoadingManager.js @@ -69,6 +69,13 @@ class LoadingManager { */ this.onError = onError; + /** + * Used for aborting ongoing requests in loaders using this manager. + * + * @type {AbortController} + */ + this.abortController = new AbortController(); + /** * This should be called by any loader using the manager when the loader * starts loading an item. @@ -269,6 +276,22 @@ class LoadingManager { }; + /** + * Can be used to abort ongoing loading requests in loaders using this manager. + * The abort only works if the loaders implement {@link Loader#abort} and `AbortSignal.any()` + * is supported in the browser. + * + * @return {LoadingManager} A reference to this loading manager. + */ + this.abort = function () { + + this.abortController.abort(); + this.abortController = new AbortController(); + + return this; + + }; + } }