210 introduced a new VolumeLoadError type to let us rigorously express any errors that might happen while loading volume data. But due to multiple problems with the way volume loading works, not all of those errors were actually possible to catch. This PR makes changes to ensure that, no matter where errors happen, a client package (i.e. website-3d-cell-viewer) always has a way to learn about it.
Problem 1: Callbacks
When a loader loads volume data (as opposed to metadata), we generally make simultaneous requests for every individual channel (or batch of channels) in a volume. Internally, this looks like firing off an async closure for every (batch of) channels we're trying to load and then immediately returning, relying on a callback to get channel data back once it's loaded. Trouble is, those closures end up basically floating in space with no connection back to the original call that initiated them.
To resolve this, I changed the signature of loadVolumeData to return a Promise<void> which represents the load operation in progress, and which therefore must only resolve when all requested channels have loaded. Assuming that promise is implemented sensibly, if one of those channel loads errors, that error should result in the promise rejecting, letting anyone await-ing the promise catch that error.
Implementing this required a moderate rework to the way ThreadableVolumeLoader works, and therefore to the interface between VolumeLoadWorker and the main thread (via VolumeLoaderContext).
Problem 2: Implicit loading
Even if every error generated by a loader can be caught, not every call to the loader is accessible to the client: many (most now) are made implicitly on a change to some other setting - time, region, scale level, etc. I added the ability to set a load error handler on View3d to capture errors on these implicit loads. This handler gets attached to a Volume via the pre-existing VolumeDataObserver path.
Review time: moderate (~30min)
210 introduced a new
VolumeLoadError
type to let us rigorously express any errors that might happen while loading volume data. But due to multiple problems with the way volume loading works, not all of those errors were actually possible to catch. This PR makes changes to ensure that, no matter where errors happen, a client package (i.e. website-3d-cell-viewer) always has a way to learn about it.Problem 1: Callbacks
When a loader loads volume data (as opposed to metadata), we generally make simultaneous requests for every individual channel (or batch of channels) in a volume. Internally, this looks like firing off an async closure for every (batch of) channels we're trying to load and then immediately returning, relying on a callback to get channel data back once it's loaded. Trouble is, those closures end up basically floating in space with no connection back to the original call that initiated them.
To resolve this, I changed the signature of
loadVolumeData
to return aPromise<void>
which represents the load operation in progress, and which therefore must only resolve when all requested channels have loaded. Assuming that promise is implemented sensibly, if one of those channel loads errors, that error should result in the promise rejecting, letting anyoneawait
-ing the promise catch that error.Implementing this required a moderate rework to the way
ThreadableVolumeLoader
works, and therefore to the interface betweenVolumeLoadWorker
and the main thread (viaVolumeLoaderContext
).Problem 2: Implicit loading
Even if every error generated by a loader can be caught, not every call to the loader is accessible to the client: many (most now) are made implicitly on a change to some other setting - time, region, scale level, etc. I added the ability to set a load error handler on
View3d
to capture errors on these implicit loads. This handler gets attached to aVolume
via the pre-existingVolumeDataObserver
path.