Most computations in LiteMol are wrapped in a Computation
class (defined in LiteMol.Core.Computation
namespace).
Computation
is a wrapper around a Promise
that provides facilities
for progress tracking. Unlike a Promise
, a Computation
is deferred,
meaning it has to be run manually using the run
function. To create a Computation
it is required to provide a Promise
that
produces the desired result.
The use of the Computation
is probably best shown using examples:
async function sumComputation() {
return Core.computation<number>(async ctx => {
let sum = 0;
for (let i = 0; i < 10; i++) {
await ctx.updateProgress(`Computing sum...`, true /* abortable */, i, 10);
sum += i;
}
return sum;
});
}
There are a few ways of consuming the computation. If we don't care about the progress, we could simply call
sumComputation().run().then(sum => console.log(sum));
or inside an async
function:
let sum = await sumComputation().run();
console.log(sum);
To use the progress tracking, there are two options:
-
Manually creating
Context
object:let ctx = LiteMol.Core.Computation.createContext(); ctx.progress.subscribe(p => console.log(p)); let sum = await sumComputation().run(ctx); console.log(sum);
-
Using
runWithContext
instead ofrun
:let comp = sumComputation().runWithContext(); comp.progress.subscribe(p => console.log(p)); let sum = await comp.result; console.log(sum);
The computation context object can be reused in multiple computations to merge their progress reporting:
let ctx = LiteMol.Core.Computation.createContext();
let a = await cA.run(ctx);
let b = await cB.run(ctx);
// ...
Optionally, computations support aborting that is built into the updateProgress
function.
This can be achieved by calling Context.requestAbort()
function (or Progress.abort()
if defined).
The next time the updateProgress
function is called, it will throw 'Aborted'
resulting
in termination of the computation. The "abort function" can be customized as shown
for example, in the ajaxGetInternal
function in Bootstrap/Utils/DataSource.ts.
Exceptions are automatically propagated using Promise.catch
.
async function badBadComputation() {
return Core.computation<number>(async ctx => {
throw Error('I am an error');
});
}
badBadComputation().run().catch(e => console.error(e));
Tasks are simply wrappers around the Computation
object that raise started/completed/updated
events that can be easily handled by the user interface. When creating a task, it is required to specify its name, type, and computation:
let task = Bootstrap.Task.create<number>('Sum', 'Background', async ctx => ...);
or
let task = Bootstrap.Task.fromComputation('Sum', 'Background', sumComputation());
There are 3 types of computations:
Normal
- Reports progress in a way that blocks the user interface (i.e. in an overlay). For example, computing new visual that takes long time.Background
- Reported in a non-blocking way. For example, downloading new data.Silent
- No reporting done.
Additionally, timing of tasks can be automatically reported using the Task.setReportTime()
function:
let task = Bootstrap.Task.fromComputation('Sum', 'Background', sumComputation())
.setReportTime(true);
Tasks are run and consumed in a fashion similar to computations with the difference
that they need to be provided a Bootstrap.Context
object to enable raising
of the events:
let plugin = Plugin.create(...);
let task = ...;
let result = await task.run(plugin.context);
Similarly to the Computation
, runWithContext
is provided that enables
to call the function tryAbort()
:
let plugin = Plugin.create(...);
let task = ...;
let running = task.runWithContext(plugin.context);
...
let result = await running.result;
// somewhere else
running.tryAbort();