# 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.