mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
More spec-compliant execution of microtasks
Summary: Changelog: [internal] This modifies the method to run microtasks in `RuntimeScheduler_Modern` to align a bit better with the spec. In this case, we'll check if we're already running microtasks when we call that method, and skip if that's the case. We're not currently calling this method recursively so this shouldn't really be a change with the current logic. Reviewed By: javache Differential Revision: D54302537 fbshipit-source-id: ef5e12e68e0c7f8c9258929609c050ef78e4cde5
This commit is contained in:
committed by
Facebook GitHub Bot
parent
4d982dcdae
commit
21171222eb
+42
-35
@@ -11,45 +11,12 @@
|
||||
#include <cxxreact/ErrorUtils.h>
|
||||
#include <react/featureflags/ReactNativeFeatureFlags.h>
|
||||
#include <react/renderer/debug/SystraceSection.h>
|
||||
#include <react/utils/OnScopeExit.h>
|
||||
#include <utility>
|
||||
#include "ErrorUtils.h"
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
namespace {
|
||||
/**
|
||||
* This is partially equivalent to the "Perform a microtask checkpoint" step in
|
||||
* the Web event loop. See
|
||||
* https://html.spec.whatwg.org/multipage/webappapis.html#perform-a-microtask-checkpoint.
|
||||
*
|
||||
* Iterates on \c drainMicrotasks until it completes or hits the retries bound.
|
||||
*/
|
||||
void executeMicrotasks(jsi::Runtime& runtime) {
|
||||
SystraceSection s("RuntimeScheduler::executeMicrotasks");
|
||||
|
||||
uint8_t retries = 0;
|
||||
// A heuristic number to guard infinite or absurd numbers of retries.
|
||||
const static unsigned int kRetriesBound = 255;
|
||||
|
||||
while (retries < kRetriesBound) {
|
||||
try {
|
||||
// The default behavior of \c drainMicrotasks is unbounded execution.
|
||||
// We may want to make it bounded in the future.
|
||||
if (runtime.drainMicrotasks()) {
|
||||
break;
|
||||
}
|
||||
} catch (jsi::JSError& error) {
|
||||
handleJSError(runtime, error, true);
|
||||
}
|
||||
retries++;
|
||||
}
|
||||
|
||||
if (retries == kRetriesBound) {
|
||||
throw std::runtime_error("Hits microtasks retries bound.");
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
#pragma mark - Public
|
||||
|
||||
RuntimeScheduler_Modern::RuntimeScheduler_Modern(
|
||||
@@ -298,7 +265,7 @@ void RuntimeScheduler_Modern::executeTask(
|
||||
|
||||
if (ReactNativeFeatureFlags::enableMicrotasks()) {
|
||||
// "Perform a microtask checkpoint" step.
|
||||
executeMicrotasks(runtime);
|
||||
performMicrotaskCheckpoint(runtime);
|
||||
}
|
||||
|
||||
if (ReactNativeFeatureFlags::batchRenderingUpdatesInEventLoop()) {
|
||||
@@ -339,4 +306,44 @@ void RuntimeScheduler_Modern::executeMacrotask(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is partially equivalent to the "Perform a microtask checkpoint" step in
|
||||
* the Web event loop. See
|
||||
* https://html.spec.whatwg.org/multipage/webappapis.html#perform-a-microtask-checkpoint.
|
||||
*
|
||||
* Iterates on \c drainMicrotasks until it completes or hits the retries bound.
|
||||
*/
|
||||
void RuntimeScheduler_Modern::performMicrotaskCheckpoint(
|
||||
jsi::Runtime& runtime) {
|
||||
SystraceSection s("RuntimeScheduler::performMicrotaskCheckpoint");
|
||||
|
||||
if (performingMicrotaskCheckpoint_) {
|
||||
return;
|
||||
}
|
||||
|
||||
performingMicrotaskCheckpoint_ = true;
|
||||
OnScopeExit restoreFlag([&]() { performingMicrotaskCheckpoint_ = false; });
|
||||
|
||||
uint8_t retries = 0;
|
||||
// A heuristic number to guard infinite or absurd numbers of retries.
|
||||
const static unsigned int kRetriesBound = 255;
|
||||
|
||||
while (retries < kRetriesBound) {
|
||||
try {
|
||||
// The default behavior of \c drainMicrotasks is unbounded execution.
|
||||
// We may want to make it bounded in the future.
|
||||
if (runtime.drainMicrotasks()) {
|
||||
break;
|
||||
}
|
||||
} catch (jsi::JSError& error) {
|
||||
handleJSError(runtime, error, true);
|
||||
}
|
||||
retries++;
|
||||
}
|
||||
|
||||
if (retries == kRetriesBound) {
|
||||
throw std::runtime_error("Hits microtasks retries bound.");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace facebook::react
|
||||
|
||||
+3
@@ -178,6 +178,9 @@ class RuntimeScheduler_Modern final : public RuntimeSchedulerBase {
|
||||
|
||||
void updateRendering();
|
||||
|
||||
bool performingMicrotaskCheckpoint_{false};
|
||||
void performMicrotaskCheckpoint(jsi::Runtime& runtime);
|
||||
|
||||
/*
|
||||
* Returns a time point representing the current point in time. May be called
|
||||
* from multiple threads.
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
template <typename Lambda>
|
||||
class OnScopeExit {
|
||||
public:
|
||||
explicit OnScopeExit(const Lambda&& lambda) noexcept
|
||||
: lambda_(std::move(lambda)) {}
|
||||
|
||||
// Non-movable
|
||||
OnScopeExit(const OnScopeExit&) = delete;
|
||||
OnScopeExit(OnScopeExit&&) = delete;
|
||||
|
||||
// Non-copyable
|
||||
OnScopeExit& operator=(const OnScopeExit&) = delete;
|
||||
OnScopeExit& operator=(OnScopeExit&&) = delete;
|
||||
|
||||
~OnScopeExit() noexcept {
|
||||
lambda_();
|
||||
}
|
||||
|
||||
private:
|
||||
Lambda lambda_;
|
||||
};
|
||||
|
||||
} // namespace facebook::react
|
||||
Reference in New Issue
Block a user