Threads
Heavy calculations on the main thread freeze the page: no scrolling, no clicks, no animations until they finish. Thread moves that work to a background thread (a Web Worker) with a small class-based API, in the spirit of Java’s Thread.
A first thread
Section titled “A first thread”Extend Thread and override two methods:
run(params)does the work. It runs inside the worker.onMessage(event)receives the results. It runs on the main thread.
import { Thread, EventBus } from "jops-core";
export default class PrimeThread extends Thread { run(params) { // runs in a Web Worker: only params and worker globals are available let count = 0; for (let n = 2; n < params.limit; n++) { let prime = true; for (let d = 2; d * d <= n; d++) { if (n % d === 0) { prime = false; break; } } if (prime) count++; } self.postMessage(count); }
onMessage(event) { // runs on the main thread EventBus.send("primes:done", event.data); }}Start it with parameters, and stop it when it is no longer needed:
const thread = new PrimeThread();thread.start({ limit: 1_000_000 });
// later, for example in a view's destroy()thread.terminate();start(params?) spawns the worker, runs run(params) in it and wires onMessage() for the results. terminate() stops the worker immediately.
run() is self-contained
Section titled “run() is self-contained”run() is serialized with toString() and executed inside the worker. That means it has no access to the outer scope:
- no imports, no closures over variables in your module,
- no
thisfrom the instance, - only its own
paramsand the globals that exist inside a worker (self.postMessage(),Math,fetch()and so on).
Pass everything it needs through params, and send results back with self.postMessage().
Showing results in a view
Section titled “Showing results in a view”Combine a thread with the EventBus: onMessage() sends an event, and the view subscribes to it.
import { View, EventBus, layout } from "jops-core";import PrimeThread from "./PrimeThread.js";
export default class Stats extends View { constructor() { super(); this.layout = layout`<p id="primes">Counting…</p>`; this.inflate(); }
onLayout() { EventBus.subscribe(this, "primes:done", (count) => { this.get("primes").set(layout`${count} primes`); }); this.thread = new PrimeThread(); this.thread.start({ limit: 1_000_000 }); }
destroy() { this.thread.terminate(); super.destroy(); }}