Skip to content

Commit 36f2788

Browse files
committed
Loader: Add abort().
1 parent 8275091 commit 36f2788

File tree

4 files changed

+117
-2
lines changed

4 files changed

+117
-2
lines changed

src/loaders/FileLoader.js

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,14 @@ class FileLoader extends Loader {
5555
*/
5656
this.responseType = '';
5757

58+
/**
59+
* Used for aborting requests.
60+
*
61+
* @private
62+
* @type {AbortController}
63+
*/
64+
this._abortController = new AbortController();
65+
5866
}
5967

6068
/**
@@ -121,7 +129,7 @@ class FileLoader extends Loader {
121129
const req = new Request( url, {
122130
headers: new Headers( this.requestHeader ),
123131
credentials: this.withCredentials ? 'include' : 'same-origin',
124-
// An abort controller could be added within a future PR
132+
signal: this._abortController.signal
125133
} );
126134

127135
// record states ( avoid data race )
@@ -338,6 +346,19 @@ class FileLoader extends Loader {
338346

339347
}
340348

349+
/**
350+
* Aborts ongoing fetch requests.
351+
*
352+
* @return {FileLoader} A reference to this instance.
353+
*/
354+
abort() {
355+
356+
this._abortController.abort();
357+
358+
return this;
359+
360+
}
361+
341362
}
342363

343364

src/loaders/ImageBitmapLoader.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@ class ImageBitmapLoader extends Loader {
6666
*/
6767
this.options = { premultiplyAlpha: 'none' };
6868

69+
/**
70+
* Used for aborting requests.
71+
*
72+
* @private
73+
* @type {AbortController}
74+
*/
75+
this._abortController = new AbortController();
76+
6977
}
7078

7179
/**
@@ -154,6 +162,7 @@ class ImageBitmapLoader extends Loader {
154162
const fetchOptions = {};
155163
fetchOptions.credentials = ( this.crossOrigin === 'anonymous' ) ? 'same-origin' : 'include';
156164
fetchOptions.headers = this.requestHeader;
165+
fetchOptions.signal = this._abortController.signal;
157166

158167
const promise = fetch( url, fetchOptions ).then( function ( res ) {
159168

@@ -191,6 +200,19 @@ class ImageBitmapLoader extends Loader {
191200

192201
}
193202

203+
/**
204+
* Aborts ongoing fetch requests.
205+
*
206+
* @return {ImageBitmapLoader} A reference to this instance.
207+
*/
208+
abort() {
209+
210+
this._abortController.abort();
211+
212+
return this;
213+
214+
}
215+
194216
}
195217

196218
export { ImageBitmapLoader };

src/loaders/Loader.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,21 @@ class Loader {
6161
*/
6262
this.requestHeader = {};
6363

64+
//
65+
66+
if ( manager.enableAbortManagement === true ) {
67+
68+
manager.addEventListener( 'abort', () => this.abort() );
69+
70+
}
71+
6472
}
6573

6674
/**
6775
* This method needs to be implemented by all concrete loaders. It holds the
6876
* logic for loading assets from the backend.
6977
*
78+
* @abstract
7079
* @param {string} url - The path/URL of the file to be loaded.
7180
* @param {Function} onLoad - Executed when the loading process has been finished.
7281
* @param {onProgressCallback} [onProgress] - Executed while the loading is in progress.
@@ -97,6 +106,7 @@ class Loader {
97106
* This method needs to be implemented by all concrete loaders. It holds the
98107
* logic for parsing the asset into three.js entities.
99108
*
109+
* @abstract
100110
* @param {any} data - The data to parse.
101111
*/
102112
parse( /* data */ ) {}
@@ -171,6 +181,18 @@ class Loader {
171181

172182
}
173183

184+
/**
185+
* This method can be implemented in loaders for aborting ongoing requests.
186+
*
187+
* @abstract
188+
* @return {Loader} A reference to this instance.
189+
*/
190+
abort() {
191+
192+
return this;
193+
194+
}
195+
174196
}
175197

176198
/**

src/loaders/LoadingManager.js

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
import { EventDispatcher } from '../core/EventDispatcher.js';
2+
3+
/**
4+
* Fires when {@link LoadingManager#abort} is called.
5+
*
6+
* @event LoadingManager#abort
7+
* @type {Object}
8+
*/
9+
const _abort = { type: 'abort' };
10+
111
/**
212
* Handles and keeps track of loaded and pending data. A default global
313
* instance of this class is created and used by loaders if not supplied
@@ -15,7 +25,7 @@
1525
* const loader2 = new ColladaLoader( manager );
1626
* ```
1727
*/
18-
class LoadingManager {
28+
class LoadingManager extends EventDispatcher {
1929

2030
/**
2131
* Constructs a new loading manager.
@@ -26,6 +36,8 @@ class LoadingManager {
2636
*/
2737
constructor( onLoad, onProgress, onError ) {
2838

39+
super();
40+
2941
const scope = this;
3042

3143
let isLoading = false;
@@ -69,6 +81,14 @@ class LoadingManager {
6981
*/
7082
this.onError = onError;
7183

84+
/**
85+
* Whether loading requests can be aborted with {@link LoadingManager#abort} or not.
86+
*
87+
* @type {boolean}
88+
* @default false
89+
*/
90+
this.enableAbortManagement = false;
91+
7292
/**
7393
* This should be called by any loader using the manager when the loader
7494
* starts loading an item.
@@ -269,6 +289,36 @@ class LoadingManager {
269289

270290
};
271291

292+
/**
293+
* Can be used to abort ongoing loading requests in loaders using this manager.
294+
* The abort only works if {@link LoadingManager#enableAbortManagement} is set
295+
* to `true` and the loaders implement {@link Loader#abort}.
296+
*
297+
* @fires LoadingManager#abort
298+
* @return {LoadingManager} A reference to this loading manager.
299+
*/
300+
this.abort = function () {
301+
302+
this.dispatchEvent( _abort );
303+
304+
return this;
305+
306+
};
307+
308+
/**
309+
* Frees internal resources. Call this method whenever this instance is no
310+
* longer used in your app.
311+
*
312+
* @return {LoadingManager} A reference to this loading manager.
313+
*/
314+
this.dispose = function () {
315+
316+
this._listeners = {}; // remove abort handler
317+
318+
return this;
319+
320+
};
321+
272322
}
273323

274324
}

0 commit comments

Comments
 (0)