FilesService & batches
This page explains how thermal files travel from a URL or an uploaded File to a rendered image: how the loading is batched, how the results are cached and how the binary data meets its parser.
How loading works
Every file load goes through the same pipeline:
- Request – your code calls
registry.batch.request()(recommended) ormanager.service.loadFile()directly. - Batching – the
BatchLoadercollects all requests registered within a single tick into oneBatch. - Fetch & cache – for each URL, the
FilesServiceeither returns a cached result, hooks into an already pending request, or fetches the file. - Parser determination – the binary content is matched against the registered parsers (LRC, FLIR). The parser may convert the file into a working buffer (FLIR JPEGs are decoded at this point).
- Result – the pipeline produces an AbstractFileResult: either a ThermalFileReader (success) or a ThermalFileFailure (failure).
- Instance creation – for each successful result, the batch calls
reader.createInstance( group ), producing a ThermalFileInstance registered in the target ThermalGroup. - Post-processing – after all files of the batch are processed, the registry recalculates group and registry min/max, imposes the range and rebuilds the histogram (
registry.postLoadedProcessing()).
registry.batch.request( url, visibleUrl, group, callback )
│ (all requests from one tick collect into one Batch)
▼
FilesService.loadFile( url )
│ cache hit? ──► cached ThermalFileReader
│ pending? ──► promise of the running request
▼
fetch( url ) ──► determineAndPrepare( buffer, url )
│ │ no parser found / parsing error
▼ ▼
ThermalFileReader ThermalFileFailure
│
▼
reader.createInstance( group ) ──► ThermalFileInstance
│
▼
registry.postLoadedProcessing() ──► minmax, range, histogramFilesService
The FilesService is a singleton per ThermalManager, available as manager.service. Registries alias it through registry.service. It performs the actual fetching, parser determination and caching.
Caching
The service holds two internal maps:
- Cache of results (
cacheByUrl) – every result ofloadFile()is stored by its URL. A second request of the same URL within the same manager returns the very same ThermalFileReader object without fetching or parsing again. The cache is shared by all registries and groups of the manager, so loading the same file into five groups downloads and parses it only once. - Pending requests (
requestsByUrl) – while a URL is being fetched, concurrent requests of the same URL hook into the running request instead of starting a new one. One URL therefore never triggers two parallel fetches.
Inspection helpers:
manager.service.fileIsInCache( "/files/klokan.lrc" ); // boolean
manager.service.fileIsPending( "/files/klokan.lrc" ); // boolean
manager.service.cachedServicesCount; // number of cached results
manager.service.requestsCount; // number of pending requestsThere is a second caching level inside every reader: the parsed base info of a file is cached in the reader itself – see ThermalFileReader.
Relation to parsers
The service does not understand any file format itself. When a file arrives, the service iterates the registered parsers and asks each one whether it recognises the content (every parser implements a static is( buffer, url ) check). The first matching parser is assigned to the file.
Some formats need a conversion step before they can be used: a radiometric FLIR JPEG is decoded into an internal binary form. For this purpose, a parser may define a prepare() method that turns the downloaded buffer into a working buffer. The resulting ThermalFileReader then keeps both buffers – the working one for parsing, and the original one for downloads.
If no parser matches, or the preparation fails, the load resolves with a ThermalFileFailure; errors are never thrown out of loadFile().
See Supported files for the list of formats and Writing a custom parser for registering a new one.
Methods
loadFile( thermalUrl, visibleUrl? )– load one file from a URL (with caching & deduplication as described above). ReturnsPromise<ThermalFileReader | ThermalFileFailure>.loadFiles( files )– load multiple URLs at once; each item may carry its own async callback.loadUploadedFile( file: File )– process aFileobtained from an upload or drag&drop. Uploaded files bypass the URL cache.handleDropzone( element, multiple? )– create a drag&drop listener on an HTML element that feeds dropped files into the service.
Use the batch loader
loadFile() returns a reader, not an instance, and does not trigger any registry post-processing. In application code, prefer registry.batch.request(), which handles instance creation and post-processing for you.
Batch loading
Each ThermalRegistry owns a lazy-loaded BatchLoader available as registry.batch. A batch is created from all requests registered within a single tick – when you request ten files in one loop, they form one batch, load in parallel, and the registry recalculates its min/max, range and histogram only once at the end.
import {
ThermalManager,
ThermalFileInstance,
ThermalFileFailure
} from "@labirthermal/core";
const manager = new ThermalManager();
const registry = manager.registries.addOrGetRegistry( "display-set" );
const group = registry.groups.addOrGetGroup( "series" );
// All requests made in this tick join the same batch
[ "/files/klokan.lrc", "/files/makak.lrc" ].forEach( url => {
registry.batch.request(
url,
undefined, // optional visible-spectrum image URL
group,
async ( result: ThermalFileInstance | ThermalFileFailure ) => {
if ( result instanceof ThermalFileInstance ) {
const container = document.createElement( "div" );
document.body.appendChild( container );
result.mountToDom( container );
} else {
console.error( "File load failed:", result.message );
}
}
);
} );How a batch executes
The batch starts automatically in the next tick after the last request() call, or immediately when it is closed. It then:
- Loads every queued URL through
FilesService.loadFile()and creates its ThermalFileInstance in the target group. Every file runs this pipeline independently in parallel, so one slow download does not delay the processing of the other files. Unexpected errors of a single file are converted to a ThermalFileFailure instead of aborting the whole batch. - Runs
registry.postLoadedProcessing()once, after all files of the batch settle. - Fires the per-file callbacks with either the instance or the ThermalFileFailure. A throwing callback does not block the remaining callbacks.
- Fires
onBatchCompleteon the loader andonResolveon the batch, and removes the batch. This happens even when something fails, so the registry never stays in the loading state forever.
While any batch is loading, the observable registry.loading property is true. It turns false only after the last loading batch finishes.
Methods
registry.batch.request( thermalUrl, visibleUrl, group, callback, id? )– register a file request; opens a new batch when none is open. Passing anidtargets a named batch. A request arriving after its batch started loading joins (or opens) a new batch instead.registry.batch.createBatch( id? )/registry.batch.getBatchById( id )– manual batch management. A batch that already started loading is sealed;getBatchByIdthen creates a new batch with the same ID.registry.batch.closeBatch()– seal the currently open batch and execute it immediately instead of waiting for the next tick; subsequent requests form a new batch.registry.batch.numberOfBatches,registry.batch.hasLoadingBatches,registry.batch.numLoadingBatches– inspection getters.
Events
registry.batch.onBatchComplete– CallbacksManager called with the array of all results whenever any batch finishes.batch.onResolve– CallbacksManager on an individualBatchobject (returned byrequest()), called with the batch's results when it finishes.registry.loading.addListener( id, value => ... )– observable loading state of the registry.registry.onProcessingStart/registry.onProcessingEnd– CallbacksManagers fired around the registry post-processing.
Example
The example below shows an implementation of FilesService and BatchLoader using the @labirthermal/webcomponents package. Both file-provider elements register their URLs in the same tick, so both files load in one batch and the registry range is calculated only once – see the context providers guide.