Make Task.call API simpler (#50545)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/50545

All usages of Task.call involve a Runnable which returns another Task, which we then extract using `.continueWithTask(Task::getResult)`. Instead inline this behaviour inside `Task.call` to avoid allocation of unnecessary intermediate objects.

Changelog: [Internal]

Reviewed By: rshest

Differential Revision: D72600051

fbshipit-source-id: 7e7c0c8e1de24b1aeff7addab2eb10272bc73ddb
This commit is contained in:
Pieter De Baets
2025-04-11 03:05:00 -07:00
committed by Facebook GitHub Bot
parent 26e89cf9e3
commit bf8d6da101
2 changed files with 61 additions and 47 deletions
@@ -231,7 +231,7 @@ public class ReactHostImpl implements ReactHost {
*/
@Override
public TaskInterface<Void> start() {
return Task.call(this::getOrCreateStartTask, mBGExecutor).continueWithTask(Task::getResult);
return Task.call(this::getOrCreateStartTask, mBGExecutor);
}
/** Initialize and run a React Native surface in a background without mounting real views. */
@@ -488,37 +488,36 @@ public class ReactHostImpl implements ReactHost {
public TaskInterface<Void> reload(String reason) {
final String method = "reload()";
return Task.call(
() -> {
Task<Void> reloadTask = null;
if (mDestroyTask != null) {
log(method, "Waiting for destroy to finish, before reloading React Native.");
reloadTask =
mDestroyTask
.continueWithTask(task -> getOrCreateReloadTask(reason), mBGExecutor)
.makeVoid();
} else {
reloadTask = getOrCreateReloadTask(reason).makeVoid();
}
() -> {
Task<Void> reloadTask = null;
if (mDestroyTask != null) {
log(method, "Waiting for destroy to finish, before reloading React Native.");
reloadTask =
mDestroyTask
.continueWithTask(task -> getOrCreateReloadTask(reason), mBGExecutor)
.makeVoid();
} else {
reloadTask = getOrCreateReloadTask(reason).makeVoid();
}
return reloadTask.continueWithTask(
task -> {
if (task.isFaulted()) {
final Exception ex = task.getError();
Assertions.assertNotNull(ex, "Reload failed without an exception");
if (mUseDevSupport) {
mDevSupportManager.handleException(ex);
} else {
mReactHostDelegate.handleInstanceException(ex);
}
return getOrCreateDestroyTask("Reload failed", ex);
}
return reloadTask.continueWithTask(
task -> {
if (task.isFaulted()) {
final Exception ex = task.getError();
Assertions.assertNotNull(ex, "Reload failed without an exception");
if (mUseDevSupport) {
mDevSupportManager.handleException(ex);
} else {
mReactHostDelegate.handleInstanceException(ex);
}
return getOrCreateDestroyTask("Reload failed", ex);
}
return task;
},
mBGExecutor);
},
mBGExecutor)
.continueWithTask(Task::getResult);
return task;
},
mBGExecutor);
},
mBGExecutor);
}
@DoNotStrip
@@ -601,19 +600,18 @@ public class ReactHostImpl implements ReactHost {
public TaskInterface<Void> destroy(String reason, @Nullable Exception ex) {
final String method = "destroy()";
return Task.call(
() -> {
if (mReloadTask != null) {
log(
method,
"Reloading React Native. Waiting for reload to finish before destroying React"
+ " Native.");
return mReloadTask.continueWithTask(
task -> getOrCreateDestroyTask(reason, ex), mBGExecutor);
}
return getOrCreateDestroyTask(reason, ex);
},
mBGExecutor)
.continueWithTask(Task::getResult);
() -> {
if (mReloadTask != null) {
log(
method,
"Reloading React Native. Waiting for reload to finish before destroying React"
+ " Native.");
return mReloadTask.continueWithTask(
task -> getOrCreateDestroyTask(reason, ex), mBGExecutor);
}
return getOrCreateDestroyTask(reason, ex);
},
mBGExecutor);
}
private MemoryPressureListener createMemoryPressureListener(ReactInstance reactInstance) {
@@ -1111,8 +1109,7 @@ public class ReactHostImpl implements ReactHost {
* destroying, will wait until destroy is finished, before creating.
*/
private Task<ReactInstance> getOrCreateReactInstance() {
return Task.call(this::waitThenCallGetOrCreateReactInstanceTask, mBGExecutor)
.continueWithTask(Task::getResult);
return Task.call(this::waitThenCallGetOrCreateReactInstanceTask, mBGExecutor);
}
@ThreadConfined("ReactHost")
@@ -297,12 +297,29 @@ public class Task<TResult> : TaskInterface<TResult> {
* Invokes the callable using the given executor, returning a Task to represent the operation.
*/
@JvmStatic
public fun <TResult> call(callable: Callable<TResult>, executor: Executor): Task<TResult> {
public fun <TResult> call(
callable: Callable<Task<TResult>>,
executor: Executor
): Task<TResult> {
val tcs = TaskCompletionSource<TResult>()
try {
executor.execute {
val continuation = Continuation { task: Task<TResult> ->
when {
task.isCancelled() -> tcs.setCancelled()
task.isFaulted() -> tcs.setError(task.getError())
else -> tcs.setResult(task.getResult())
}
}
try {
tcs.setResult(callable.call())
val task = callable.call()
synchronized(task.lock) {
if (task.isCompleted()) {
continuation.then(task)
} else {
task.continuations.add(continuation)
}
}
} catch (e: CancellationException) {
tcs.setCancelled()
} catch (e: Exception) {