Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/GoogleChromeLabs/clooney

Clooney is an actor library for the web. Use workers without thinking about workers.
https://github.com/GoogleChromeLabs/clooney

Last synced: about 2 months ago
JSON representation

Clooney is an actor library for the web. Use workers without thinking about workers.

Awesome Lists containing this project

README

        

# Clooney
Clooney is an actor (ayooo) library for the web. Classes given to Clooney will be instantiated and run in a worker, keeping the main thread responsive.

> ⚠️ **Caveat:** The class cannot rely on its surrounding scope, since it is executed in an isolated context. This might change once workers support ES6 modules.

## Quickstart
An example says more than 1000 words:

```html

(async function() {
class MyRemoteClass {
doExpensiveCalculation(a, b) {
return a + b;
}
}

const instance = await Clooney.spawn(MyRemoteClass);
console.log(await instance.doExpensiveCalculation(5, 23));
})();

```

I’m collecting more examples of Clooney in action in [this Glitch](https://clooney-examples.glitch.me/).

## Browser support

Clooney uses [Comlink] under the hood, and so inherits its browser compatibility matrix.

![Chrome 56+](https://img.shields.io/badge/Chrome-56+-green.svg?style=flat-square)
![Edge 15+](https://img.shields.io/badge/Edge-15+-green.svg?style=flat-square)
![Firefox 52+](https://img.shields.io/badge/Firefox-52+-green.svg?style=flat-square)
![Opera 43+](https://img.shields.io/badge/Opera-43+-green.svg?style=flat-square)
![Safari 10.1+](https://img.shields.io/badge/Safari-10.1+-green.svg?style=flat-square)
![Samsung Internet 6.0+](https://img.shields.io/badge/Samsung_Internet-6.0+-green.svg?style=flat-square)

Browsers without [ES6 Proxy] support can use the [proxy-polyfill].

## Events and Functions
Functions and events are not transferable (i.e. can’t be sent from to a worker), but Clooney has special handling for them:

```js
class MyRemoteClass {
onClick(remoteEvent) {
// … react to click …
}
}

const instance = await Clooney.spawn(MyRemoteClass);
const button = document.querySelector('button');
button.addEventListener('click', instance.onClick.bind(instance));
```

The `remoteEvent` object is a mangled version of the original event to make it transferable:

```js
const remoteEvent = {
targetId, // = event.target.id
targetClassList, // = [...event.target.classList]
detail, // = event.detail
data // = event.data
};
```

## Promises and async methods
Clooney handles promises (and therefore, async methods) automatically:

```js
class Actor {
timeoutThing() {
return new Promise(resolve => setTimeout(_ => resolve('ohai'), 1000));
}
}

const instance = await strategy.spawn(Actor);
alert(await instance.timeoutThing()); // Will alert() after 1 second
```

## API
Clooney’s job is to take _actors_ (class definitions) and _spawn_ those actors in _containers_ ([Web Workers][Web Worker]). You can use that instance as if it was a local instance (this is magic provided by [Comlink]).

### `Clooney.spawn(class, constructorArgs)`
This call is equivalent to `Clooney.defaultStrategy.spawn(class, constructorArgs)`. Clooney creates an instance of `RoundRobinStrategy` as the default strategy.

### Strategies
Strategies decide how many containers are spun up and where a new instance is created.

```typescript
export interface Strategy {
/**
* `spawn` instantiates the given actor in an actor container of the strategy’s choice.
* @returns The return type is the type as T, but every method is implicitly async.
*/
spawn(actor: new () => T, constructorArgs: any[], opts: Object): Promise;
/**
* `terminate` calls `terminate()` on all existing containers of the strategy.
*/
terminate(): Promise;
}
```

#### `Clooney.RoundRobinStrategy(opts)`
`RoundRobinStrategy` creates up to n containers and cycles through the containers with every `spawn` call. `RoundRobinStrategy` is the default strategy.

### Strategy Options

- `maxNumContainers`: Maximum number of containers to create (default: 1)
- `newWorkerFunc`: Asynchronous function that creates a new container (default: `new Worker(Clooney.defaultWorkerSrc)`)

### `Clooney.asRemoteValue(obj)`

`asRemoteValue` marks a value. If a marked value is used as an parameter or return value, it will not be transferred but instead proxied.

## CDN
If you want to use Clooney from a CDN, you need to work around the same-origin restrictions that workers have:

```html

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});
// Business as usual using strategy.spawn() ...

```

[Comlink]: https://github.com/GoogleChromeLabs/comlink
[Web Worker]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API
[es6 proxy]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
[proxy-polyfill]: https://github.com/GoogleChrome/proxy-polyfill

---
License Apache-2.0