Replies: 7 comments 8 replies
-
Would being able to do things like storage access (sqlite, react-native-mmkv) and making HTTP calls be something that would be considered for support in the future? |
Beta Was this translation helpful? Give feedback.
-
One of the most complicated things in RN development is freeing main event loop, which often includes all kind of operations except the UI. For example, download and parse a sizable JSON, merging it into the some kind of store (and diffing to make react perform), writing to disk, etc - the only way right now is to move to native. The Web Worker model would be perfect - keeps a lot of flexibility, it is still a single file as worklets. The perfect threading would be:
|
Beta Was this translation helpful? Give feedback.
-
on the Web we have the concept of transferable objects for worker <-> main thread data transfer of e.g. large arrays in O(1) (see the section in the link regarding zero-copy operation for ArrayBuffers), as basically ownership (and just a pointer) is transferred. As my usecase (something akin to crossfilter.js but in RN on the native layer) requires transfer of potentially very large data arrays (of numbers) to the worklet, is this already solved with the concepts introduced here? It seems so, but like to know for sure (otherwise something like transferable objects would be my request) |
Beta Was this translation helpful? Give feedback.
-
I have to sync bunch of data from Apple health kit to my database. For this use case fps drops sometimes. Is this good usage for that? |
Beta Was this translation helpful? Give feedback.
-
What's the difference between |
Beta Was this translation helpful? Give feedback.
-
It seems like Reanimated is working on react-native-worklets |
Beta Was this translation helpful? Give feedback.
-
This could elevate the React Native ecosystem to a whole new level. It would benefit everyone if Hermes supported a built-in worker thread model—similar to the one that works out of the box in Node.js. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
The Idea of React Native Worklets and Its JavaScript API
Abstract
react-native-worklets is a multithreading library for React Native. It allows to run JavaScript code on multiple JavaScript runtimes and threads. Its primary responsibility is to spawn and manage the UI Runtime – a JavaScript runtime for running worklets on the UI thread.
The purpose of this document is to provide a high-level overview of the desired react-native-worklets' functionalities available in JavaScript as well as a brief explanation of its mental model and limitations. The ideas aren't set in stone and we would be more than happy to iterate on the feedback received from the community.
The discussion about its native API will be facilitated in another document.
Terms
React Native Runtime
Referred to as RN Runtime. It is the JavaScript Runtime that executes your app's bundle and where the React part of React Native lives.
UI Thread
Also called the Main Thread. It is the only thread that has synchronous access to native events and the native rendering layer.
JS Thread
The thread that is primarily tasked with the continuous execution of the RN Runtime.
Closure
In a JavaScript function you can use variables defined outside of this function. A collection of these variables and the function are collectively referred to as a closure. You can read more about closures here. Sometimes we refer only to the closure's variables as closure.
Worklet
A short JavaScript function (closure), which can be executed on a JavaScript runtime different from the runtime of its origin.
Worklet Runtime
A JavaScript runtime spawned by react-native-worklets. It's pre-configured to be able to execute worklets. It isn't coupled to any thread, but there might be a thread dedicated to its execution.
UI Runtime
A unique Worklet Runtime that is tailored to efficiently offload work from the RN Runtime and to allow for synchronous access to native events and the native rendering layer.
Why
Worklets were created for smooth animations and handling gestures in react-native-reanimated and react-native-gesture-handler. Over time, we noticed the limitations of its implementation. The multithreading model, tightly coupled with animations and gestures, proved difficult to maintain and exceptionally challenging to expand. Moreover, the community found more applications of worklets than we previously anticipated like processing camera frames, drawing on the Skia canvas and synchronous text formatting. A natural conclusion was to create a separate library with clearly defined boundaries and interfaces.
We received numerous pieces of feedback from the community about the fact that react-native-reanimated is too large to function effectively as a singular entity. This has been a pain point for web apps aiming for the smallest possible bundle size. It was also counterintuitive that, to delegate a resource-heavy task to another thread, you had to use an animation library that added countless features you weren't interested in using but which nevertheless impacted your app.
This is also an opportunity for us, the Reanimated team, to "start over" and make some things right. The multithreading part of react-native-reanimated had occasionally been confusing for our users. It wasn't always clear whether something was executed synchronously, asynchronously, or whether a graphical glitch was due to a bug or an ill-written user animation. We aim to retain a minimalist, seamless API while placing a significantly greater emphasis on its cost and understandability.
How
We plan to implement the API and concepts described in this document gradually. In the initial iterations of react-native-worklets, we'll maintain the APIs known from react-native-reanimated, such as
runOnUI
,runOnJS
, etc. These will eventually get deprecated and dropped over time.While we aim to create a library that would be symmetric across all Worklet Runtimes, early on we want to focus on the most important feature of react-native-worklets — the UI Runtime. Therefore, general features that aren't specific to the UI Runtime might lag behind for a few iterations.
Threading
JavaScript runtimes aren't tied to a specific thread. We like to think of them as of not thread-safe resources. Therefore, a thread must acquire a given runtime exclusively, which could lead to costly preemptions and even deadlocks in ill-written code. We want to reflect these costs in the API design. To address the transparency issues, we plan to embrace the
async
/await
syntax to hint to the user about what might be going on under the hood.scheduleOnUI
A function that schedules a worklet on the UI Runtime, to be executed on the UI thread. It doesn't return a value nor directly inform you if the callback has been executed.
It serves as a direct replacement for the current
runOnUI
.Example usage
runOnUIAsync
A function that schedules a worklet on the UI Runtime, to be executed on the UI thread. It returns a Promise of the worklet's return value. The Promise is resolved asynchronously, not immediately after the callback execution.
Example usage
runOnUISync
A function that executes a worklet synchronously on the UI Runtime on the current thread. It might preempt the UI Runtime from the UI thread, potentially being expensive. It returns the callback's return value.
Example usage
scheduleOnRN
A function that schedules a worklet on the RN Runtime. The execution thread is decided by React Native, likely to be the JS thread. It doesn't return a value nor inform you directly whether the callback has been executed.
Example usage
runOnRNAsync
A function that schedules a worklet on the RN Runtime. It returns a Promise of the worklet's return value. The execution thread is decided by React Native, likely to be the JS thread. The Promise is resolved asynchronously, not immediately after the callback execution.
runOnRNSync
A function that executes a worklet on the RN Runtime synchronously. It returns the callback's result. Execution may result in thread switching and preempting the RN Runtime, potentially being expensive.
scheduleOnRuntime
A function that schedules a worklet on a given Worklet Runtime, which will be executed on its dedicated thread. It doesn't return a value nor informs you directly whether the callback has been executed or not. This function cannot target the RN Runtime or the UI Runtime.
runOnRuntimeAsync
A function that schedules a worklet on a given Worklet Runtime to be executed on its dedicated thread. It returns a Promise of the worklet's return value. The Promise is resolved asynchronously, not immediately after the callback execution. This function cannot target the RN Runtime or the UI Runtime.
runOnRuntimeSync
A function that executes a worklet synchronously on a specified Worklet Runtime on the current thread. This might preempt the Worklet Runtime from its thread, potentially being expensive. It returns the callback's return value. This function cannot target the RN Runtime or the UI Runtime.
Passing arguments to worklets
The public methods described previously are designed for parameter-less worklets. This is the most common case for using worklets, a shorthand API. To use worklets with arguments or to memoize the callback, use the
worklet
API.worklet
A function that creates a worklet from a provided function. The worklet can be called with arguments.
Example usage
The key difference of calling a worklet with parameters compared to using implicit closure is that the worklet's closure is immutable. See the following comparison:
Using
worklet
directly allows for efficient memoization:Methods
scheduleOnUI
runOnUIAsync
runOnUISync
scheduleOnRN
runOnRNAsync
runOnRNSync
scheduleOnRuntime
runOnRuntimeAsync
runOnRuntimeSync
The methods behave just like their previous respective counterparts.
Memory Sharing
Sharing memory between JavaScript runtimes is a complex topic; therefore, we'll focus only on discussing the key ideas relevant to the API. react-native-worklets introduces three key concepts, Serializables, Shareables and Synchronizables.
Shared Values (Mutables)
After thorough consideration, we decided that Shared Values will remain in Reanimated. They are objects specifically implemented for animations, creating a graph of inputs and outputs, which is irrelevant to multithreading. Instead, react-native-worklets will provide APIs that allow for implementing Shared Values and other objects that preserve a state across a given Worklet Runtime and are easily accessible from other Worklet Runtimes or the RN Runtime.
Serializable
A Serializable is an object that can be copied to Worklet Runtimes. It returns the reference to the Serializable. The reference cannot be manipulated, as it doesn't represent any standard JavaScript object. Changes to the original value don't affect the Serializable. To prevent misconceptions about it we freeze the original value.
createSerializable
A function that creates a Serializable from a given value. Conceptually, you don't need to use this function as react-native-worklets handles Serializable creation and management for you.
Example usage
For exotic use cases, you can create a Serializable that holds a value different from the original.
Shareable
A Shareable is an object which can be assigned to a specific Worklet Runtime, where it's shared across worklets. Accessing a Shareable on a runtime different from the assigned runtime means reading or modifying it on a different Worklet Runtime. A Shareable cannot hold a function.
createShareable
A function that creates a Shareable from a given value. It returns the reference to the Shareable.
A Shareable has the following methods:
getAsync
- returns a Promise of the value held by the Shareable, similar torunOn...Async
functions.getSync
- returns the value held by the Shareable, similar torunOn...Sync
functions.setAsync
- asynchronously sets the value of the Shareable on the Shareable's Worklet Runtime; similarscheduleOn...
functions. You can pass a worklet as an argument to modify the Shareable in place efficiently.setSync
- synchronously sets the value of Shareable on the Shareable's Worklet Runtime; similar torunOn...Sync
functions. You can pass a worklet as an argument to modify the Shareable in place efficiently.A Shareable can be initiated with a value or an initializer worklet, which runs on the assigned Worklet Runtime.
Example usage
Modifying in place
To understand the key differences between Serializables and Shareables, consider the following example:
Synchronizable
A Synchronizable is a shared memory not tied to any JavaScript Runtime. It can be accessed from any JavaScript Runtime and C++. The type of the value cannot be changed. It can be obtained exclusively or non-exclusively, therefore trying to access it from multiple threads at once could lead to blocking.
Synchronizable is an advanced concept. It's useful when you need to access shared memory from C++ often, as it doesn't need to do intermediate calls to JavaScript. If you mainly need access in JavaScript, use a Shareable instead for better performance.
A Synchronizable has the following methods:
setDirty
orsetBlocking
are being executed on another thread.setDirty
orsetBlocking
are being executed on another thread, therefore could result in a dirty read.getBlocking
,setBlocking
orsetDirty
are being executed on another thread.getBlocking
orsetBlocking
are being executed on another thread. It doesn't block whensetDirty
is executed on another thread, therefore could result in a lost update.createSynchronizable
A function that creates a Synchronizable from a given value. It returns the reference to the Synchronizable.
Example usage
Scheduling part was omitted.
Runtimes
Our community has asked us for more granular process of creating and managing the Worklet Runtimes. Therefore, we're overhauling the API for more specialized use cases. We'll follow the same pattern when expanding the native API of the Worklet Runtimes. Old API of
createWorkletRuntime
will be dropped and replaced with a new one.createWorkletRuntime
A function that creates a Worklet Runtime, accordingly to a provided configuration.
The configuration object has the following properties:
Example usage
Events
While handling native events synchronously - like screen taps - is one of the key features of react-native-worklets, we plan to preserve all event handling APIs (useEvent etc.) in react-native-reanimated. The existing JavaScript implementation of event handling is very (React) component-specific, and initially react-native-worklets should not inherit any component-specific code. However, we are open to discussing this feature in the future iterations of react-native-worklets.
Reanimated Babel plugin
Renamed to Worklets Babel plugin, available to import from react-native-worklets. For convenience it's reexported from react-native-reanimated but with a meaningful deprecation message.
Future
With react-native-worklets as a separate library, not tied to animations, we can finally work on adding more features to it.
Afterword
This document will be a cornerstone of the future react-native-worklets documentation. If you're interested in how some concepts work under the hood, feel free to ask questions. If an explanation of some intricacy is valuable for the user, we'd gladly add it to the documentation.
Beta Was this translation helpful? Give feedback.
All reactions