GLTFLoader abort signal integration with LoadingManager progress tracking
0 reputation · 03 Sept 2020, 01:38 UTC
0 reputation · 03 Sept 2020, 01:38 UTC
Goal: ensure that aborting a GLTFLoader request also updates LoadingManager progress and cleans up any associated callbacks.
Constraints: LoadingManager does not provide a built‑in abort mechanism; developers must manually attach an AbortSignal to each loader and manage progress events to avoid orphaned callbacks or memory leaks.
Questions: Should LoadingManager expose a way to forward an AbortSignal to all active loaders? How can developers guarantee that aborting a loader stops related LoadingManager events without leaving dangling callbacks? Is there a recommended timeout pattern that works uniformly across loaders that lack native AbortSignal support?
34775 reputation · 03 Sept 2020, 04:06 UTC
To ensure that aborting a GLTFLoader request also updates the LoadingManager and cleans up callbacks, you must manually bridge the gap between the AbortSignal and the manager's internal state. Because LoadingManager tracks the number of items loaded versus total items, a canceled request typically leaves the manager in a "pending" state, preventing the global onLoad event from ever firing.
The most reliable way to guarantee that aborting a loader stops related events without leaving dangling callbacks is to wrap the loader call in a controller that handles the AbortError specifically to notify the manager.
AbortController for each request or group of requests.signal within the options object of the GLTFLoader.load method (supported in modern Three.js versions via the underlying FileLoader).AbortError. If it is, manually trigger the logic required to "complete" that item's slot in the LoadingManager or reset the manager's state.const manager = new THREE.LoadingManager();
const loader = new THREE.GLTFLoader(manager);
const controller = new AbortController();
loader.load(
'model.glb',
(gltf) => { /* success */ },
(progress) => { /* progress */ },
(error) => {
if (error.name === 'AbortError') {
console.log('Request aborted: Cleaning up manager state...');
// Manual cleanup logic here
}
},
undefined, // options
{ signal: controller.signal } // Pass signal here
);
addEventListener attached to the AbortSignal is removed using the { once: true } option or manually in the loader's final callback to prevent memory leaks.setTimeout. When the timeout wins, call abort() on the controller and reject the promise.This approach assumes the use of a Three.js version where FileLoader propagates the signal to the fetch API. To verify this behavior:
(canceled).LoadingManager item count before and after the abort to ensure the manager is not indefinitely waiting for a file that will never arrive.Diagnostic Detail Needed: Are you using a custom FileLoader implementation or a specific Three.js version older than r150? If so, the signal may not propagate, requiring a manual override of the FileLoader.prototype.load method.
Use comments to ask for clarification. Post a solution as an answer.
34,775 reputation · 03 Sept 2020, 12:06 UTC
When you attach an AbortSignal to a GLTFLoader via loader.setSignal(signal) (available from three.js r135), the loader will cancel the underlying fetch. However, the LoadingManager does not automatically know that the item was aborted, so you must manually invoke manager.itemEnd(url) for the aborted resource to keep manager.progress accurate. To avoid orphaned callbacks, either rely on the abort to clear internal listeners or explicitly remove any custom onProgress, onError, or onLoad handlers before calling controller.abort(). This pattern works uniformly across loaders that inherit from THREE.Loader and ensures no dangling references or stalled progress bars.