mrdoob / three.js

JavaScript 3D Library.
https://threejs.org/
MIT License
101.79k stars 35.31k forks source link

Ability to cancel ongoing HTTP requests in loaders #20705

Open JohnKis opened 3 years ago

JohnKis commented 3 years ago

Is your feature request related to a problem? Please describe.

Currently it's not possible to cancel ongoing HTTP requests made by loaders. This can be an issue when paper.js is used in a context where users can navigate between models (e.g.: a 3D model gallery).

Describe the solution you'd like

An abort/cancel method on the loaders or on LoadingManager would be a great way to allow developers control to cancel requests that are no longer needed.

Describe alternatives you've considered

I created a local version of the loader I'm using (PLYLoader) and returned result of FileLoader on the load method. This works in my use-case as I'm not using caching or data urls however as I learned from #10712 file loader doesn't always return an XMLHTTPRequest so it's not a good generic solution. I raised PR #20703 with these changes but closed it because of aforementioned issues.

Additional context Another related PR: #9600

gkjohnson commented 3 years ago

I agree this would be a nice addition -- I don't think the LoadingManager is the right place to call cancel, though, because it would cancel all requests related to the manager when you might only want to cancel one.

The AbortSignal seems to be the modern way to cancel requests but it only works with the fetch API (#14073 related).

taseenb commented 3 years ago

This could be useful (fundamental) in React to avoid the dreaded "Can't perform a React state update on an unmounted component" warning. Also very similar to Dispose of loaders request: https://github.com/mrdoob/three.js/issues/20958

andresichelero commented 8 months ago

There is still no efficient way to cancel a loading (without modifying the existent loader code and repacking), which results in a waste of time when there are more than six fetch requests occurring concurrently on Chrome and it is not possible to cancel the request for files that are no longer needed.

gkjohnson commented 8 months ago

There is still no efficient way to cancel a loading

You can start a request with "fetch" that you can cancel with an abort signal and then parse the contents with the loaders "parse" function. Not as elegant as something built in and it can't cancel the other triggered requests (texture files, for example) once the pars has begun but it's still very possible. This is also the equivalent of what the previous "XMLHttpRequest.abort" approach would have afforded. This is the approach that the 3DTilesRenderer project is using.

I think it's worth elaborating on what your use case is, why you need to cancel file downloads, and metrics about the problems not being able to is causing your application (ie it's taking X seconds longer to download, we're downloading X more MB on mobile bandwidth than necessary, etc) which may help members of the project appreciate the need if there's a strong one.

andresichelero commented 7 months ago

There is still no efficient way to cancel a loading

You can start a request with "fetch" that you can cancel with an abort signal and then parse the contents with the loaders "parse" function. Not as elegant as something built in and it can't cancel the other triggered requests (texture files, for example) once the pars has begun but it's still very possible. This is also the equivalent of what the previous "XMLHttpRequest.abort" approach would have afforded. This is the approach that the 3DTilesRenderer project is using.

I think it's worth elaborating on what your use case is, why you need to cancel file downloads, and metrics about the problems not being able to is causing your application (ie it's taking X seconds longer to download, we're downloading X more MB on mobile bandwidth than necessary, etc) which may help members of the project appreciate the need if there's a strong one.

Thanks for the great answer, I'll take a look at the 3DTiles project. As for my use case, I appreciate your suggestion, and while I can't provide any code, I can write that my company works with CFD simulations and provides an API to perform such simulations in an environment with a viewer that uses Three.js. Our customers can upload .STL files (variable sizes but up to 50MB per file - multiple files allowed) and submit a simulation, and the results are saved in .GLTF files and downloaded into the viewer, showing the results as layers along with the models. There are generally more than 10 GLTF files, with the possibility of more than 50, and at least 5 STL files for each simulation. Both STL and GLTF file downloads use the standard Three.js library loaders. Because of this, the limitation of canceling the loading of an object or result layer that has been canceled or removed by the user causes considerable lag in UX.

An example is when I open a simulation: all assets begin to load, and if I change to another simulation, I can't cancel the asset loading from STLLoader and GLTFLoader, I can only invalidate their results, so other assets keep waiting, like this example:

image Here, the first three downloads are for the first simulation, and the other ones are for the second. They spent at least 15s stalled.

One might argue that faster internet can help, indeed, but it won't always be available to customers or to salespeople doing demos in random office rooms with slow wi-fi.