Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export default function RuntimeTestsExample() {
require('./tests/runtimes/runOnUISync.test');
require('./tests/runtimes/scheduleOnRuntime.test');
require('./tests/runtimes/scheduleOnUI.test');
require('./tests/runtimes/runOnRuntimeSync.test');
},
},
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import {
createSynchronizable,
createWorkletRuntime,
scheduleOnRN,
runOnRuntimeSync,
scheduleOnRuntime,
} from 'react-native-worklets';
import { describe, expect, test, notify, waitForNotification } from '../../ReJest/RuntimeTestsApi';
import { ComparisonMode } from '../../ReJest/types';

const NOTIFICATION_NAME = 'NOTIFICATION_NAME';

describe('runOnRuntimeSync', () => {
test('use runOnRuntimeSync to run a function on the Worker Runtime from RN Runtime', () => {
// Arrange
const workletRuntime = createWorkletRuntime({ name: 'test' });

// Act
const result = runOnRuntimeSync(workletRuntime, () => {
'worklet';
return 100;
});

// Assert
expect(result).toBe(100, ComparisonMode.NUMBER);
});

test('keep the correct order of execution runOnRuntimeSync and scheduleOnRuntime', async () => {
// Arrange
const workletRuntime = createWorkletRuntime({ name: 'test' });
const synchronizable = createSynchronizable(0);

const onJSCallback = () => {
notify(NOTIFICATION_NAME);
};

// Act
// TODO: Replace with `runOnRuntimeAsync`.
scheduleOnRuntime(workletRuntime, () => {
'worklet';
// heavy computation
new Array(50_000_000).map((_v, i) => i ** 2);
synchronizable.setBlocking(100);
scheduleOnRN(onJSCallback);
});

const result = runOnRuntimeSync(workletRuntime, () => {
'worklet';
return 100;
});

// Assert
expect(result).toBe(100, ComparisonMode.NUMBER);
await waitForNotification(NOTIFICATION_NAME);
expect(synchronizable.getBlocking()).toBe(100, ComparisonMode.NUMBER);
});
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 6
sidebar_position: 8
---

# createWorkletRuntime
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 4
sidebar_position: 3
---

<DeprecatedBanner
Expand Down
2 changes: 1 addition & 1 deletion packages/docs-worklets/docs/threading/getRuntimeKind.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 8
sidebar_position: 12
---

# getRuntimeKind
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 8
sidebar_position: 13
---

# isWorkletFunction
Expand Down
2 changes: 1 addition & 1 deletion packages/docs-worklets/docs/threading/runOnRuntime.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 5
sidebar_position: 9
---

<DeprecatedBanner
Expand Down
79 changes: 79 additions & 0 deletions packages/docs-worklets/docs/threading/runOnRuntimeSync.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
---
sidebar_position: 11
---

# runOnRuntimeSync

`runOnRuntimeSync` lets you run a [workletized](/docs/fundamentals/glossary#to-workletize) function synchronously on a [Worker Runtime](/docs/fundamentals/glossary#worker-worklet-runtime---worker-runtime).
It might preempt the Runtime where it's called from the thread (it's blocking).
Comment on lines +7 to +8
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
`runOnRuntimeSync` lets you run a [workletized](/docs/fundamentals/glossary#to-workletize) function synchronously on a [Worker Runtime](/docs/fundamentals/glossary#worker-worklet-runtime---worker-runtime).
It might preempt the Runtime where it's called from the thread (it's blocking).
`runOnRuntimeSync` lets you run a [workletized](/docs/fundamentals/glossary#to-workletize) function synchronously on a [Worker Runtime](/docs/fundamentals/glossary#worker-worklet-runtime---worker-runtime). It's blocking - meaning that it can preempt the runtime from a thread that's currently executing it.

## Reference

```javascript
import { runOnRuntimeSync, createWorkletRuntime } from 'react-native-worklets';

const workletRuntime = createWorkletRuntime({ name: 'background' });

const result = runOnRuntimeSync(workletRuntime, () => {
'worklet';
return 2+2;
}); // This will block the RN Runtime until the worklet is finished

console.log(result); // 4
```


<details>
<summary>Type definitions</summary>

```typescript
function runOnRuntimeSync<Args extends unknown[], ReturnValue>(
workletRuntime: WorkletRuntime,
worklet: (...args: Args) => ReturnValue,
...args: Args
): ReturnValue
```

</details>

## Arguments

### workletRuntime

The worklet runtime to run the worklet on.

### worklet

A reference to a function you want to execute on the [Worklet Runtime](/docs/fundamentals/glossary#worklet-runtime).

### args

Arguments to the function you want to execute on the [Worklet Runtime](/docs/fundamentals/glossary#worklet-runtime).

## Remarks

- `runOnRuntimeSync` can only be called on the [RN Runtime](/docs/fundamentals/glossary#react-native-runtime) unless the [Bundle Mode](/docs/experimental/bundleMode) is enabled.

```javascript
import { createWorkletRuntime, runOnRuntimeSync } from 'react-native-worklets';

const workletRuntime = createWorkletRuntime({ name: 'background' });

runOnUI(() => {
runOnRuntimeSync(workletRuntime, (greeting: string) => {
console.log(`${greeting} from the background Worklet Runtime`);
}, 'Hello'); // This will throw an error outside of Bundle Mode 🚨
});
```

```javascript
import { createWorkletRuntime, scheduleOnRuntime } from 'react-native-worklets';

const workletRuntime = createWorkletRuntime({ name: 'background' });
const anotherWorkletRuntime = createWorkletRuntime({ name: 'anotherBackground' });

runOnRuntimeSync(anotherWorkletRuntime, () => {
runOnRuntimeSync(workletRuntime, (greeting: string) => {
console.log(`${greeting} from the background Worklet Runtime`);
}, 'Hello'); // This will throw an error outside of Bundle Mode 🚨
});
```
2 changes: 1 addition & 1 deletion packages/docs-worklets/docs/threading/runOnUIAsync.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 3
sidebar_position: 4
---

# runOnUIAsync
Expand Down
2 changes: 1 addition & 1 deletion packages/docs-worklets/docs/threading/runOnUISync.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 10
sidebar_position: 5
---

# runOnUISync
Expand Down
2 changes: 1 addition & 1 deletion packages/docs-worklets/docs/threading/scheduleOnRN.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 9
sidebar_position: 7
---

# scheduleOnRN
Expand Down
4 changes: 2 additions & 2 deletions packages/docs-worklets/docs/threading/scheduleOnRuntime.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 12
sidebar_position: 10
---

# scheduleOnRuntime
Expand Down Expand Up @@ -74,6 +74,6 @@ const anotherWorkletRuntime = createWorkletRuntime({ name: 'anotherBackground' }
scheduleOnRuntime(anotherWorkletRuntime, () => {
scheduleOnRuntime(workletRuntime, (greeting: string) => {
console.log(`${greeting} from the background Worklet Runtime`);
}, 'Hello'); // This will throw an error 🚨
}, 'Hello'); // This will throw an error outside of Bundle Mode 🚨
});
```
2 changes: 1 addition & 1 deletion packages/docs-worklets/docs/threading/scheduleOnUI.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 11
sidebar_position: 6
---

# scheduleOnUI
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,15 @@ inline jsi::Value executeOnUIRuntimeSync(
return jsi::Value::undefined();
}

inline jsi::Value runOnRuntimeSync(
jsi::Runtime &rt,
const jsi::Value &workletRuntimeValue,
const jsi::Value &serializableWorkletValue) {
auto workletRuntime =
workletRuntimeValue.getObject(rt).getHostObject<WorkletRuntime>(rt);
return workletRuntime->executeSync(rt, serializableWorkletValue);
}

inline jsi::Value createWorkletRuntime(
jsi::Runtime &originRuntime,
const std::shared_ptr<RuntimeManager> &runtimeManager,
Expand Down Expand Up @@ -202,6 +211,7 @@ std::vector<jsi::PropNameID> JSIWorkletsModuleProxy::getPropertyNames(
propertyNames.emplace_back(jsi::PropNameID::forAscii(rt, "scheduleOnUI"));
propertyNames.emplace_back(
jsi::PropNameID::forAscii(rt, "executeOnUIRuntimeSync"));
propertyNames.emplace_back(jsi::PropNameID::forAscii(rt, "runOnRuntimeSync"));
propertyNames.emplace_back(
jsi::PropNameID::forAscii(rt, "createWorkletRuntime"));
propertyNames.emplace_back(
Expand Down Expand Up @@ -496,6 +506,17 @@ jsi::Value JSIWorkletsModuleProxy::get(
});
}

if (name == "runOnRuntimeSync") {
return jsi::Function::createFromHostFunction(
rt,
propName,
2,
[](jsi::Runtime &rt,
const jsi ::Value &thisValue,
const jsi::Value *args,
size_t count) { return runOnRuntimeSync(rt, args[0], args[1]); });
}

if (name == "createWorkletRuntime") {
return jsi::Function::createFromHostFunction(
rt,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,11 +164,12 @@ jsi::Value WorkletRuntime::executeSync(
auto serializableWorklet = extractSerializableOrThrow<SerializableWorklet>(
rt,
worklet,
"[Worklets] Only worklets can be executed synchronously on UI runtime.");
"[Worklets] Only worklets can be executed synchronously on Worklet (" +
name_ + ") Runtime.");
auto lock = std::unique_lock<std::recursive_mutex>(*runtimeMutex_);
jsi::Runtime &uiRuntime = getJSIRuntime();
jsi::Runtime &workletRuntime = getJSIRuntime();
auto result = runGuarded(serializableWorklet);
auto serializableResult = extractSerializableOrThrow(uiRuntime, result);
auto serializableResult = extractSerializableOrThrow(workletRuntime, result);
lock.unlock();
return serializableResult->toJSValue(rt);
}
Expand Down
46 changes: 46 additions & 0 deletions packages/react-native-worklets/__typetests__/runOnRuntimeSync.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { createWorkletRuntime, runOnRuntimeSync, runOnUISync } from '..';

function runOnRuntimeSyncTypeTests() {
const workletRuntime = createWorkletRuntime({ name: 'test' });
// Correct usage - correct usage
runOnRuntimeSync(
workletRuntime,
(num: number): number => {
return num + 1;
},
0
);

// @ts-expect-error - expected no args, but arg is provided
runOnRuntimeSync(workletRuntime, (): void => {}, 0);

// Wrong args type
runOnRuntimeSync(
workletRuntime,
(num: number): number => {
return num + 1;
},
// @ts-expect-error - wrong args type
'tets'
);

// Wrong return type
runOnRuntimeSync(
workletRuntime,
(num: number): string => {
// @ts-expect-error - wrong return type
return num + 1;
},
0
);

// @ts-expect-error - wrong return type
const result: string = runOnRuntimeSync(
workletRuntime,
(num: number): number => {
return num + 1;
},
0
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,12 @@ class JSWorklets implements IWorkletsModule {
);
}

runOnRuntimeSync(): never {
throw new WorkletsError(
'`runOnRuntimeSync` is not available in JSWorklets.'
);
}

createWorkletRuntime(): never {
throw new WorkletsError(
'createWorkletRuntime is not available in JSWorklets.'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,13 @@ See https://docs.swmansion.com/react-native-worklets/docs/guides/troubleshooting
);
}

runOnRuntimeSync<TValue, TReturn>(
workletRuntime: WorkletRuntime,
worklet: SerializableRef<TValue>
): TReturn {
return this.#workletsModuleProxy.runOnRuntimeSync(workletRuntime, worklet);
}

createSynchronizable<TValue>(value: TValue): SynchronizableRef<TValue> {
return this.#workletsModuleProxy.createSynchronizable(value);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ export interface WorkletsModuleProxy {
worklet: SerializableRef<TValue>
): void;

runOnRuntimeSync<TValue, TReturn>(
workletRuntime: WorkletRuntime,
worklet: SerializableRef<TValue>
): TReturn;

reportFatalErrorOnJS(
message: string,
stack: string,
Expand Down
1 change: 1 addition & 0 deletions packages/react-native-worklets/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export { getRuntimeKind, RuntimeKind } from './runtimeKind';
export {
createWorkletRuntime,
runOnRuntime,
runOnRuntimeSync,
scheduleOnRuntime,
} from './runtimes';
export { createSerializable, isSerializableRef } from './serializable';
Expand Down
Loading
Loading