mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-01-12 22:50:10 +08:00
TM iOS: force flush message queue when calling into JS from native
Summary: When calling into JS (e.g. promise resolve/reject, callback) in TurboModule, we bypass the bridge's message queue. At times this causes race condition, where there are a bunch of pending UI operations (in RCTUImanager) waiting to be flushed, but nothing adds calls to the message queue. Usually tapping the screen will trigger the flush because we're sending down touch events to JS. Reviewed By: JoshuaGross Differential Revision: D14656466 fbshipit-source-id: cb3a174e97542bf80f0a37b4170b6a8e6780fa35
This commit is contained in:
committed by
Facebook Github Bot
parent
1592acd4a9
commit
a43e666a34
@@ -210,6 +210,11 @@ struct RCTInstanceCallback : public InstanceCallback {
|
||||
return _jsMessageThread;
|
||||
}
|
||||
|
||||
- (std::shared_ptr<Instance>)reactInstance
|
||||
{
|
||||
return _reactInstance;
|
||||
}
|
||||
|
||||
- (BOOL)isInspectable
|
||||
{
|
||||
return _reactInstance ? _reactInstance->isInspectable() : NO;
|
||||
|
||||
@@ -180,5 +180,12 @@ void Instance::handleMemoryPressure(int pressureLevel) {
|
||||
nativeToJsBridge_->handleMemoryPressure(pressureLevel);
|
||||
}
|
||||
|
||||
void Instance::invokeAsync(std::function<void()>&& func) {
|
||||
nativeToJsBridge_->runOnExecutorQueue([func=std::move(func)](JSExecutor *executor) {
|
||||
func();
|
||||
executor->flush();
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
||||
|
||||
@@ -71,6 +71,8 @@ public:
|
||||
|
||||
void handleMemoryPressure(int pressureLevel);
|
||||
|
||||
void invokeAsync(std::function<void()>&& func);
|
||||
|
||||
private:
|
||||
void callNativeModules(folly::dynamic &&calls, bool isEndOfBatch);
|
||||
void loadApplication(std::unique_ptr<RAMBundleRegistry> bundleRegistry,
|
||||
|
||||
@@ -108,6 +108,8 @@ public:
|
||||
virtual void destroy() {}
|
||||
virtual ~JSExecutor() {}
|
||||
|
||||
virtual void flush() {}
|
||||
|
||||
static std::string getSyntheticBundlePath(
|
||||
uint32_t bundleId,
|
||||
const std::string& bundlePath);
|
||||
|
||||
@@ -83,9 +83,10 @@ public:
|
||||
* Synchronously tears down the bridge and the main executor.
|
||||
*/
|
||||
void destroy();
|
||||
private:
|
||||
|
||||
void runOnExecutorQueue(std::function<void(JSExecutor*)> task);
|
||||
|
||||
private:
|
||||
// This is used to avoid a race condition where a proxyCallback gets queued
|
||||
// after ~NativeToJsBridge(), on the same thread. In that case, the callback
|
||||
// will try to run the task on m_callback which will have been destroyed
|
||||
|
||||
@@ -103,10 +103,11 @@ class JSIExecutor : public JSExecutor {
|
||||
invokee();
|
||||
}
|
||||
|
||||
void flush() override;
|
||||
|
||||
private:
|
||||
class NativeModuleProxy;
|
||||
|
||||
void flush();
|
||||
void bindBridge();
|
||||
void callNativeModules(const jsi::Value &queue, bool isEndOfBatch);
|
||||
jsi::Value nativeCallSyncHook(const jsi::Value *args, size_t count);
|
||||
|
||||
@@ -7,20 +7,19 @@
|
||||
|
||||
#include "JSCallInvoker.h"
|
||||
|
||||
#include <cxxreact/MessageQueueThread.h>
|
||||
#include <cxxreact/Instance.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
JSCallInvoker::JSCallInvoker(std::shared_ptr<MessageQueueThread> jsThread)
|
||||
: jsThread_(jsThread) {}
|
||||
JSCallInvoker::JSCallInvoker(std::shared_ptr<Instance> reactInstance)
|
||||
: reactInstance_(reactInstance) {}
|
||||
|
||||
void JSCallInvoker::invokeAsync(std::function<void()>&& func) {
|
||||
jsThread_->runOnQueue(std::move(func));
|
||||
}
|
||||
|
||||
void JSCallInvoker::invokeSync(std::function<void()>&& func) {
|
||||
jsThread_->runOnQueueSync(std::move(func));
|
||||
if (reactInstance_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
reactInstance_->invokeAsync(std::move(func));
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
|
||||
@@ -13,25 +13,26 @@
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
class MessageQueueThread;
|
||||
class Instance;
|
||||
|
||||
/**
|
||||
* A generic native-to-JS call invoker. It guarantees that any calls from any
|
||||
* thread are queued on the right JS thread.
|
||||
*
|
||||
* For now, this is a thin-wrapper around existing MessageQueueThread. Eventually,
|
||||
* For now, this is a thin-wrapper around existing bridge (`Instance`). Eventually,
|
||||
* it should be consolidated with Fabric implementation so there's only one
|
||||
* API to call JS from native, whether synchronously or asynchronously.
|
||||
* Also, this class should not depend on `Instance` in the future.
|
||||
*/
|
||||
class JSCallInvoker {
|
||||
public:
|
||||
JSCallInvoker(std::shared_ptr<MessageQueueThread> jsThread);
|
||||
JSCallInvoker(std::shared_ptr<Instance> reactInstance);
|
||||
|
||||
void invokeAsync(std::function<void()>&& func);
|
||||
void invokeSync(std::function<void()>&& func);
|
||||
// TODO: add sync support
|
||||
|
||||
private:
|
||||
std::shared_ptr<MessageQueueThread> jsThread_;
|
||||
std::shared_ptr<Instance> reactInstance_;
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
class Instance;
|
||||
|
||||
/**
|
||||
* ObjC++ specific TurboModule base class.
|
||||
*/
|
||||
@@ -89,5 +91,6 @@ private:
|
||||
@interface RCTBridge ()
|
||||
|
||||
- (std::shared_ptr<facebook::react::MessageQueueThread>)jsMessageThread;
|
||||
- (std::shared_ptr<facebook::react::Instance>)reactInstance;
|
||||
|
||||
@end
|
||||
|
||||
@@ -51,7 +51,7 @@ static Class getFallbackClassFromName(const char *name) {
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_runtime = runtime;
|
||||
_jsInvoker = std::make_shared<react::JSCallInvoker>(bridge.jsMessageThread);
|
||||
_jsInvoker = std::make_shared<react::JSCallInvoker>(bridge.reactInstance);
|
||||
_delegate = delegate;
|
||||
_bridge = bridge;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user