diff --git a/ReactCommon/react/renderer/runtimescheduler/BUCK b/ReactCommon/react/renderer/runtimescheduler/BUCK index 4435282ca38..9afa55191fb 100644 --- a/ReactCommon/react/renderer/runtimescheduler/BUCK +++ b/ReactCommon/react/renderer/runtimescheduler/BUCK @@ -50,5 +50,6 @@ rn_xplat_cxx_library( deps = [ react_native_xplat_target("runtimeexecutor:runtimeexecutor"), react_native_xplat_target("react/renderer/debug:debug"), + react_native_xplat_target("better:better"), ], ) diff --git a/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler.cpp b/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler.cpp index 6200d5957a7..21cc21a2888 100644 --- a/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler.cpp +++ b/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler.cpp @@ -22,4 +22,8 @@ void RuntimeScheduler::scheduleTask(std::shared_ptr const &task) { }); } +void RuntimeScheduler::cancelTask(const std::shared_ptr &task) { + task->cancel(); +} + } // namespace facebook::react diff --git a/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler.h b/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler.h index 78ee02dc5ce..26fb4d5309d 100644 --- a/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler.h +++ b/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler.h @@ -20,6 +20,8 @@ class RuntimeScheduler final { void scheduleTask(std::shared_ptr const &task); + void cancelTask(std::shared_ptr const &task); + private: mutable std::priority_queue< std::shared_ptr, diff --git a/ReactCommon/react/renderer/runtimescheduler/RuntimeSchedulerBinding.cpp b/ReactCommon/react/renderer/runtimescheduler/RuntimeSchedulerBinding.cpp index 801f28c5b70..fa69b7d1f7f 100644 --- a/ReactCommon/react/renderer/runtimescheduler/RuntimeSchedulerBinding.cpp +++ b/ReactCommon/react/renderer/runtimescheduler/RuntimeSchedulerBinding.cpp @@ -70,6 +70,20 @@ jsi::Value RuntimeSchedulerBinding::get( }); } + if (propertyName == "unstable_cancelCallback") { + return jsi::Function::createFromHostFunction( + runtime, + name, + 1, + [this]( + jsi::Runtime &runtime, + jsi::Value const &, + jsi::Value const *arguments, + size_t) noexcept -> jsi::Value { + runtimeScheduler_.cancelTask(taskFromValue(runtime, arguments[0])); + return jsi::Value::undefined(); + }); + } if (propertyName == "unstable_ImmediatePriority") { return jsi::Value(runtime, serialize(SchedulerPriority::ImmediatePriority)); } @@ -91,6 +105,7 @@ jsi::Value RuntimeSchedulerBinding::get( return jsi::Value(runtime, serialize(SchedulerPriority::IdlePriority)); } + react_native_assert(false && "undefined property"); return jsi::Value::undefined(); } diff --git a/ReactCommon/react/renderer/runtimescheduler/Task.cpp b/ReactCommon/react/renderer/runtimescheduler/Task.cpp index aa97dd92106..c220fa1b79c 100644 --- a/ReactCommon/react/renderer/runtimescheduler/Task.cpp +++ b/ReactCommon/react/renderer/runtimescheduler/Task.cpp @@ -16,8 +16,18 @@ SchedulerPriority Task::getPriority() const { return priority_; } +void Task::cancel() { + // Null out the callback to indicate the task has been canceled. (Can't + // remove from the priority_queue because you can't remove arbitrary nodes + // from an array based heap, only the first one.) + callback_.reset(); +} + void Task::operator()(jsi::Runtime &runtime) const { - callback_.call(runtime, {}); + if (callback_) { + // Cancelled task doesn't have a callback. + callback_.value().call(runtime, {}); + } } } // namespace facebook::react diff --git a/ReactCommon/react/renderer/runtimescheduler/Task.h b/ReactCommon/react/renderer/runtimescheduler/Task.h index 1573c76059a..ddfde802572 100644 --- a/ReactCommon/react/renderer/runtimescheduler/Task.h +++ b/ReactCommon/react/renderer/runtimescheduler/Task.h @@ -7,6 +7,7 @@ #pragma once +#include #include #include @@ -16,12 +17,14 @@ class Task final { public: Task(SchedulerPriority priority, jsi::Function callback); - SchedulerPriority priority_; - jsi::Function callback_; - SchedulerPriority getPriority() const; + void cancel(); void operator()(jsi::Runtime &runtime) const; + + private: + SchedulerPriority priority_; + better::optional callback_; }; class TaskPriorityComparer { diff --git a/ReactCommon/react/renderer/runtimescheduler/primitives.h b/ReactCommon/react/renderer/runtimescheduler/primitives.h index c56971a3b63..76794941452 100644 --- a/ReactCommon/react/renderer/runtimescheduler/primitives.h +++ b/ReactCommon/react/renderer/runtimescheduler/primitives.h @@ -26,4 +26,14 @@ inline static jsi::Value valueFromTask( runtime, std::make_shared(task)); } +inline static std::shared_ptr taskFromValue( + jsi::Runtime &runtime, + jsi::Value const &value) { + if (value.isNull()) { + return nullptr; + } + + return value.getObject(runtime).getHostObject(runtime)->task; +} + } // namespace facebook::react