tick listener parses a 50 MB file, nobody else
ticks and nobody draws. So the host times every call it makes into your script, and when one runs far
too long, it stops it.
Heavy work doesn’t belong on that thread. Move it into a Worker: its own thread, no limits,
and it can’t freeze anyone.
Limits
Only time spent in JavaScript (and WebAssembly) counts. Waiting on the disk (
fs, WASI
syscalls) or in an FFI call doesn’t.
The loading row is the one you want for setup. This works, even if the parse takes eight seconds:
await settles, or 30 seconds after the script started at the latest.
When a call hits its limit, it is stopped mid-flight and the script goes into the error state. Its
listeners, timers and everything else it owns are released, and the log says which call it was. The
script doesn’t recover from this: its state was cut off halfway through, so reload it.
Worker
postMessage.
url is relative to your entry module’s folder (dist/ for a typical build). A file:/// URL works
too, so the bundler idiom new Worker(new URL("./parser.js", import.meta.url)) does what you’d expect.
It has to be inside the script folder.
What a worker has
- No time limits. It only stops when you call
terminate(), it callsclose(), it throws at the top level or runs out of memory, or your script unloads. postMessage,onmessage,close(),self.name, timers,console,fetch,WebSocket,crypto, compression streams,WebAssembly, and@native/fsand@native/wasi.- Not the game: no
@native/render,entities,game,ui,esp,memory,ffi, nolocalStorage, notick/renderevents, no nested workers. Do that part in the script and post the results across.
Messages
Messages are structured clones, so you get copies of objects, arrays, Maps, typed arrays, errors and so on. Functions and class instances don’t survive the trip.- Transfer an
ArrayBufferto move it without copying. The sender’s copy is detached. PasspostMessage(data, [buffer]), orpostMessage(data, { transfer: [buffer] })inside a worker (that form type-checks against TypeScript’s DOM types). SharedArrayBufferis shared, not copied: both sides see the same memory. UseAtomicsto coordinate.Atomics.waitblocks, so it only works inside a worker. On the script thread it throws, useAtomics.waitAsyncthere.WebAssembly.Modulearrives already compiled. Compile once in the script, instantiate in the worker.
error event on the Worker object.
preventDefault() keeps it out of the log.