Workers

The same heavy sum, run twice: once in the page and once on another thread. A number ticks every 60ms beside it, so you can see which of the two stops the screen.

The mailbox is not what stops it

JavaScript runs one thread. A computation that does not yield stops the page whoever wrote it — that has nothing to do with actors. Measured:

where the 300ms of arithmetic runsworst gap seen by another actor
this thread338 ms
a worker34 ms — the idle baseline

One line says where it runs

The actor doing the work is held through an ordinary ActorRef.

a := Worker spawn: (Adder named: '集計' to: sink) on: w.

(a ask sumTo: 100000) forced printNl.

Worker spawn:on: is the only line that says where it runs. ask and tell are written the same as for an actor on this thread. A reference does not carry where its actor lives.

What may cross was settled first

Crossing a thread copies the state and every message. A block cannot be copied, because it closes over the scope it was made in.

That stops at compile time, and it names the field that caused it:

the state placed on a worker cannot cross an actor boundary: it is Job,
whose work is Block[Int -> Int], and a block closes over the scope it was
made in

Decimal, Date and Dict cross with their meaning intact. Handing them to structuredClone would strip their prototypes and a Decimal would arrive as a bare pair of numbers — money that stopped being money on the way — so the wire format is written here rather than borrowed.

Failure crosses too

Crash an actor on a worker and the watcher gets its down:, the same as on this thread.