---
# System prepended metadata

title: Multithreading

---

# Worklet Runtime/Multithreading proposal

This proposal defines the API for running **worklets** on other **threads** than JS and UI thread which also requires the use of other **runtimes**.

Potential use cases suggested by the community: https://twitter.com/tomekzaw_/status/1691849748712444292

## Shareables

Shareables are C++ data structures which serve as an immutable runtime-agnostic intermediate format for passing serializable data between JS runtimes.

Previously, shareables would keep an instance of `JSRuntimeHelper` and behave differently across runtimes (only RN and UI runtime were supported). Adapting shareables to work with arbitrary runtimes is in scope of this feature.

## Worklet runtime

* wrapper around `std::shared_ptr<jsi::Runtime>`
* runtime-agnostic (support JSC/Hermes/V8)
* built-in debugging support (Chrome DevTools Protocol)
* has JSI bindings and core functions already injected
    * `valueUnpacker`, `callGuardDEV` -- required
    * `_scheduleOnJS`, `_makeShareableClone` -- required for `runOnJS`
    * `console.*`, `performance.*` -- optional
* provides methods to call worklets via callGuardDEV (show errors in RedBox)
* is a `jsi::HostObject` so it can be created in JS and passed to C++ side

```ts
const runtime = createWorkletRuntime("foo");
// captures `valueUnpacker` and `makeShareableClone`
// and passes it to JSI binding `_createWorkletRuntime`
// TODO: measure execution time

console.log(runtime.name); // foo
```

* we provide a function `extractWorkletRuntime` as a symbol in `libreanimated.so` to avoid problems with casting and RTTI between dynamic shared libraries on Android

```cpp
std::shared_ptr<WorkletRuntime> workletRuntime = extractWorkletRuntime(rt, hostObject);
```

* it's possible to access `jsi::Runtime &` directly
* returns a reference instead of shared pointer so that the lifetime of underlying runtime is controlled only by `WorkletRuntime` instance

```cpp
jsi::Runtime &rt = workletRuntime->getRuntime();
```

## Running worklets from C++

* that's how we will call worklets internally (in Reanimated codebase)

```cpp
std::shared_ptr<ShareableWorklet> shareableWorklet = ...;
workletRuntime->runGuarded(shareableWorklet);
```

* we will also expose the following public header:

```cpp!
// SomePublicHeader.h

namespace worklets {

class Worklet; // no need to specify fields and methods
class WorkletRuntime;  // no need to specify fields and methods

std::shared_ptr<WorkletRuntime> extractWorkletRuntime(
    jsi::Runtime &rt,
    const jsi::Value &workletRuntime);
    
std::shared_ptr<Worklet> extractWorklet(
    jsi::Runtime &rt,
    const jsi::Value &worklet);
    
std::shared_ptr<Worklet> executeWorklet(
    const std::shared_ptr<WorkletRuntime> &workletRuntime,
    const std::shared_ptr<Worklet> &worklet);

} // namespace worklets
```

* here's the actual implementation as an adapter:

```cpp
class WorkletRuntime {
  reanimated::WorkletRuntime reanimatedWorkletRuntime;
}
```

* here's the external use:

```cpp!
#include <RNWorklets/SomePublicHeader.h>

auto workletRuntime = extractWorkletRuntime(rt, hostObject);
auto worklet = extractWorklet(rt, value);
executeWorklet(workletRuntime, worklet);
```

## Running worklets from JS

* analogous API to `runOnUI` or `runOnJS`

```ts
const runtime = /* ... */;

runOnRuntime(runtime, () => {
  'worklet';
  // code executed on a system background thread
})(...args);
```

```ts
runOnRuntime(runtime, () => {
  'worklet';
  const y = f(x);
  runOnJS(callback)(y);
})(x);
```

## Background task

* not to confuse with iOS background tasks (https://developer.apple.com/documentation/backgroundtasks)

```ts!
const config = {
  runtime: /* ... */,
  // more stuff in the future
}

const result = await backgroundTask(worklet, config);
```

```ts
const result = await backgroundTask(() => {
  'worklet';
  return fib(30);
});
```

## Cancelling background tasks

We can't simply stop the backgroujnd thread or terminate the runtime in a non-consistent state. Instead, the user should explicitely mark cancellation points.

```ts!
const shouldYield = makeMutable(false);

runOnRuntime(runtime, () => {
  'worklet';
  // some code here
  if (shouldYield.value) {
    return;
  }
  // moar code here
})();

const handlePress = () => {
  shouldYield.value = true;
};
```

## Next steps

### Implement WebWorker API

https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API

```typescript
const myWorker = new Worker("worker.js");

myWorker.postMessage("ping");

onmessage = (e) => {
  console.log(e.data);
  postMessage("pong");
};

myWorker.onmessage = (e) => {
  console.log(e.data);
};
```

### Bundling worklets

This would allow using third-party libraries inside worklets.
