Clooney Web Workers: Remote Class Instances Without Boilerplate
Clooney is an actor library for the web. Use workers without thinking about workers.
At a glance
- What is it?
- Clooney moves class instances into Web Workers through a Comlink-based remote proxy, keeping long-running work off the page's main thread. It fits browser code that can isolate its state and communicate through serializable values or specially handled events.
- Who is it for?
- Adopt Clooney for browser-only workloads that can be expressed as isolated actor classes with serializable communication, especially when keeping work off the main thread matters. Do not adopt it for code that depends on closure variables, surrounding application state, or direct function transfer without redesign.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 9 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Clooney's Browser Actor Boundary
Clooney addresses a specific browser problem: JavaScript work runs on one main thread by default, so an expensive calculation can delay input, rendering, and interaction. The project takes a class definition, instantiates it inside a Web Worker, and returns a remote handle that can be called like an instance. Its own description is concise: classes given to Clooney are run in a worker while the main thread remains available for other work.
The intended users are web developers who have CPU-heavy or otherwise blocking operations but can isolate that operation into a class. This is not a general-purpose replacement for ordinary classes, nor does it automatically decide which work belongs off the main thread. The application still has to define the actor's methods, choose the placement strategy, and ensure that its inputs and outputs can cross the worker boundary.
Clooney provides a small actor-oriented layer over Web Workers and Comlink. The package metadata identifies `comlinkjs` version `3.2.0` as its runtime dependency. That distinction matters for evaluation. Developers are adopting both Clooney's class spawning and proxy behavior and the browser capabilities required by Comlink, Proxy, workers, promises, and structured browser messaging.
Class Spawning Through Comlink
The central call is `Clooney.spawn(class, constructorArgs)`. According to the API documentation, this is equivalent to `Clooney.defaultStrategy.spawn(class, constructorArgs)`. Clooney creates a `RoundRobinStrategy` by default, so the first basic flow is straightforward: define a class, spawn it, await the returned proxy, then call its methods. Method results are exposed asynchronously because the call crosses the worker boundary.
The README's quickstart defines `MyRemoteClass`, spawns it, and invokes `doExpensiveCalculation(5, 23)`. The calculation itself is only addition, so it is an API example rather than evidence of performance improvement. The architectural point is that the class can execute inside a worker without the caller managing worker creation, message channels, or Comlink's endpoint setup directly.
Clooney also supports `Clooney.asRemoteValue(obj)`. Marking a value changes its treatment: when used as an argument or return value, it is proxied rather than transferred. This is relevant for applications that pass state or service-like objects between the page and actor. The README does not explain when proxying is preferable to ordinary structured transfer, so the exact ownership and lifecycle of a remote value should be verified before relying on it.
RoundRobinStrategy Worker Placement
Worker placement is controlled by a strategy. A strategy creates up to a selected number of worker containers and decides where each new actor instance is created. `RoundRobinStrategy` cycles through those containers for successive `spawn` calls. Its default `maxNumContainers` is `1`, which means the documented default does not distribute actors across several workers unless that option is changed.
The second strategy option is `newWorkerFunc`, an asynchronous function that creates a new container. Its default is `new Worker(Clooney.defaultWorkerSrc)`. This option is the main extension point for environments where the library and worker source must be loaded differently, including a CDN deployment affected by worker same-origin restrictions. It also means worker creation is policy that the application can own instead of accepting the default unconditionally.
The `Strategy` interface includes `spawn` and `terminate`. `terminate()` calls `terminate()` on every existing container held by the strategy. This gives the caller an explicit cleanup operation for actor containers, which is useful in applications that create workers repeatedly or tie worker lifetime to a component. The interface does not document restart behavior, health checks, worker failure handling, or automatic recovery after termination, so Clooney should not be treated as a complete worker supervision system.
Loading Clooney 0.7.0 From a CDN
The README does not give an `npm install` or local build tutorial. It documents a CDN setup using `[email protected]`. Because browsers apply same-origin restrictions to workers, the example fetches the worker source as a blob and constructs the worker from the resulting object URL. The following is the complete browser loading pattern documented by the project. It installs `newWorkerFunc` on a new `RoundRobinStrategy`; the README leaves the business logic after that line unspecified.
<script src="https://cdn.jsdelivr.net/npm/[email protected]/clooney.bundle.min.js"></script>
<script>
async function newWorkerFunc() {
const blob = await fetch(Clooney.defaultWorkerSrc).then(resp => resp.blob())
return new Worker(URL.createObjectURL(blob));
}
const strategy = new Clooney.RoundRobinStrategy({newWorkerFunc});
</script>For a first actual actor call, define the class before spawning it and use the strategy returned by that call. This combines the repository's quickstart pattern with the documented CDN worker factory. The example method adds `5` and `23`, so it demonstrates remote invocation rather than a documented performance result. The call is awaited even though the method body is synchronous, reflecting the remote proxy's asynchronous API.
<script>
(async function() {
class MyRemoteClass {
doExpensiveCalculation(a, b) {
return a + b;
}
}
const instance = await Clooney.spawn(MyRemoteClass);
console.log(await instance.doExpensiveCalculation(5, 23));
})();
</script>The two snippets assume the CDN script has loaded before the second script runs. The README also links to a Glitch collection for additional examples, but it does not describe a supported package installation command.
Event and Promise Constraints at the Worker Boundary
Functions and browser events cannot be transferred between the page and worker. Clooney provides special handling for event callbacks, but the callback is not a normal local event object inside the worker. The README describes a mangled `remoteEvent` containing `targetId`, `targetClassList`, `detail`, and `data`. These fields represent selected event information rather than the complete DOM event. Code that depends on arbitrary event properties should not assume that Clooney preserves them.
The documented event pattern binds the remote method to a page button. The page sends the event to the actor, and the actor handles the reduced representation. This is a concrete data-modeling requirement: developers need to decide which event attributes cross the boundary and ensure that the actor can operate without the original event's methods or live DOM references.
Promises and `async` methods receive automatic handling. The example actor returns a promise from `setTimeout`, and the caller awaits the remote method. This makes time-delayed work expressible inside an actor, but it does not make the worker automatically cancellable. The README does not document cancellation, timeout policy, error serialization, rejection details, or worker crash behavior. Those omissions make the promise support convenient but not a complete reliability specification.
Browser Compatibility and Dependency Boundaries
The README states that Clooney uses Comlink under the hood and inherits Comlink's browser compatibility matrix. The listed minimums are Chrome 56+, Edge 15+, Firefox 52+, Opera 43+, Safari 10.1+, and Samsung Internet 6.0+. Browsers without ES6 Proxy support are directed to Google's `proxy-polyfill`. This gives adopters a concrete browser floor, but it does not address every modern browser behavior that an application might encounter.
The repository is not archived, and its last push was on 2026-10-14. The package has no GitHub releases, so there is no release history here to compare compatibility changes or migration notes. The published package version is `0.7.0`. Its development toolchain is visibly older, including TypeScript `3.5.3`, Rollup `1.20.1`, Karma `4.2.0`, and Mocha `6.2.0`; these versions establish the repository's build inputs, but the README does not say whether they affect the browser bundle at runtime.
The Apache-2.0 license permits reuse under its terms, but this review does not interpret those terms. Teams should check the included `LICENSE` file for their distribution and compliance context. The `Dockerfile` provides a test-oriented environment based on `selenium/node-chrome`, Node 8, and `npm test`, which can help reproduce the repository's intended test setup, although no test results are claimed here.
Clooney Compared With Direct Worker Code
Direct Web Worker code gives the application explicit control over worker creation, message formats, and lifecycle. An application can use the `Worker` constructor itself, post structured messages, and implement its own dispatch layer. That approach is more verbose for ordinary remote method calls, but it leaves transfer formats and failure handling visible in application code.
Clooney takes a different approach. It treats a class as an actor definition, instantiates it in a container, and exposes the instance through Comlink. The caller receives a proxy whose method calls return promises. Events and functions receive special treatment, while `Clooney.asRemoteValue` offers another communication model. This is more convenient for code shaped around actor classes, especially when multiple actors can be placed through a strategy.
The trade-off is a less explicit boundary. The class is executed in an isolated context, so closure variables and surrounding scope are unavailable. The README directly warns about this caveat. Clooney is therefore a poor fit for a class that expects to capture a page-local variable, access a DOM node through closure, or receive arbitrary functions without a compatibility design. Direct worker messaging may be the better starting point when those constraints are central.
Editorial conclusion
Adopt Clooney for browser-only workloads that can be expressed as isolated actor classes with serializable communication, especially when keeping work off the main thread matters. Do not adopt it for code that depends on closure variables, surrounding application state, or direct function transfer without redesign. Verify the required browser support, your same-origin worker loading path, the shape of event data, and termination behavior before integrating `Clooney.spawn()` into production code.
Frequently asked questions
How do I install Clooney in a browser?
The README does not provide an npm installation command. It documents loading `[email protected]` from jsDelivr and using a blob URL worker factory to work around same-origin restrictions.
Can a Clooney actor use variables from its surrounding JavaScript scope?
No. The README states that the class cannot rely on its surrounding scope because it runs in an isolated worker context. Inputs and outputs must be designed for the worker boundary.
Does Clooney support multiple workers?
Yes, through `Clooney.RoundRobinStrategy`. It creates up to `maxNumContainers` containers and cycles through them for each `spawn` call, with the default value set to `1`.
How are events handled by Clooney?
Events are not transferred as complete browser event objects. Clooney provides a mangled representation containing `targetId`, `targetClassList`, `detail`, and `data`.
What license does Clooney use?
The repository declares the Apache-2.0 license in `package.json` and includes a `LICENSE` file. The README also identifies the project as Apache-2.0 licensed.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/googlechromelabs-clooney)Was this useful?