fabric: send events via JS thread

Summary: Calling the event emitters on the main thread seems to be problematic, so let's dispatch it via the JS thread. This requires some changes to make "eventTarget" single-use because otherwise the binding would need to synchronize the actual JS call with the act of releasing the target.

Reviewed By: shergin

Differential Revision: D8375291

fbshipit-source-id: bd2b42731176ae209f4a19c232309c163fb1c01b
This commit is contained in:
Kevin Gozali 2018-06-15 10:56:38 -07:00 committed by Facebook Github Bot
parent 0883e52c74
commit 2ca4770011
8 changed files with 12 additions and 49 deletions

View File

@ -188,6 +188,11 @@ struct RCTInstanceCallback : public InstanceCallback {
return (JSGlobalContextRef)(_reactInstance ? _reactInstance->getJavaScriptContext() : nullptr);
}
- (std::shared_ptr<MessageQueueThread>)jsMessageThread
{
return _jsMessageThread;
}
- (BOOL)isInspectable
{
return _reactInstance ? _reactInstance->isInspectable() : NO;

View File

@ -30,8 +30,6 @@ public:
virtual EventTarget createEventTarget(const InstanceHandle &instanceHandle) const = 0;
virtual void releaseEventTarget(const EventTarget &eventTarget) const = 0;
/*
* Dispatches "raw" event using some event-delivery infrastructure.
*/

View File

@ -17,9 +17,7 @@ EventEmitter::EventEmitter(const InstanceHandle &instanceHandle, const Tag &tag,
tag_(tag),
eventDispatcher_(eventDispatcher) {}
EventEmitter::~EventEmitter() {
releaseEventTargetIfNeeded();
}
EventEmitter::~EventEmitter() {}
void EventEmitter::dispatchEvent(
const std::string &type,
@ -31,7 +29,7 @@ void EventEmitter::dispatchEvent(
return;
}
createEventTargetIfNeeded();
EventTarget eventTarget = createEventTarget();
// Mixing `target` into `payload`.
assert(payload.isObject());
@ -39,31 +37,13 @@ void EventEmitter::dispatchEvent(
extendedPayload.merge_patch(payload);
// TODO(T29610783): Reconsider using dynamic dispatch here.
eventDispatcher->dispatchEvent(eventTarget_, type, extendedPayload, priority);
eventDispatcher->dispatchEvent(eventTarget, type, extendedPayload, priority);
}
void EventEmitter::createEventTargetIfNeeded() const {
std::lock_guard<std::mutex> lock(mutex_);
if (eventTarget_) {
return;
}
EventTarget EventEmitter::createEventTarget() const {
auto &&eventDispatcher = eventDispatcher_.lock();
assert(eventDispatcher);
eventTarget_ = eventDispatcher->createEventTarget(instanceHandle_);
}
void EventEmitter::releaseEventTargetIfNeeded() const {
std::lock_guard<std::mutex> lock(mutex_);
if (!eventTarget_) {
return;
}
auto &&eventDispatcher = eventDispatcher_.lock();
assert(eventDispatcher);
eventDispatcher->releaseEventTarget(eventTarget_);
return eventDispatcher->createEventTarget(instanceHandle_);
}
} // namespace react

View File

@ -48,14 +48,11 @@ protected:
private:
void createEventTargetIfNeeded() const;
void releaseEventTargetIfNeeded() const;
EventTarget createEventTarget() const;
InstanceHandle instanceHandle_;
Tag tag_;
std::weak_ptr<const EventDispatcher> eventDispatcher_;
mutable EventTarget eventTarget_ {nullptr};
mutable std::mutex mutex_;
};
} // namespace react

View File

@ -98,10 +98,6 @@ void FabricUIManager::setDispatchEventFunction(std::function<DispatchEventFuncti
dispatchEventFunction_ = dispatchEventFunction;
}
void FabricUIManager::setReleaseEventTargetFunction(std::function<ReleaseEventTargetFunction> releaseEventTargetFunction) {
releaseEventTargetFunction_ = releaseEventTargetFunction;
}
void FabricUIManager::setReleaseEventHandlerFunction(std::function<ReleaseEventHandlerFunction> releaseEventHandlerFunction) {
releaseEventHandlerFunction_ = releaseEventHandlerFunction;
}
@ -119,10 +115,6 @@ void FabricUIManager::dispatchEvent(const EventTarget &eventTarget, const std::s
);
}
void FabricUIManager::releaseEventTarget(const EventTarget &eventTarget) const {
releaseEventTargetFunction_(eventTarget);
}
SharedShadowNode FabricUIManager::createNode(int tag, std::string viewName, int rootTag, folly::dynamic props, InstanceHandle instanceHandle) {
isLoggingEnabled && LOG(INFO) << "FabricUIManager::createNode(tag: " << tag << ", name: " << viewName << ", rootTag: " << rootTag << ", props: " << props << ")";

View File

@ -20,7 +20,6 @@ namespace react {
using CreateEventTargetFunction = EventTarget (InstanceHandle instanceHandle);
using DispatchEventFunction = void (EventHandler eventHandler, EventTarget eventTarget, std::string type, folly::dynamic payload);
using ReleaseEventTargetFunction = void (EventTarget eventTarget);
using ReleaseEventHandlerFunction = void (EventHandler eventHandler);
class FabricUIManager {
@ -46,14 +45,12 @@ public:
*/
void setCreateEventTargetFunction(std::function<CreateEventTargetFunction> createEventTargetFunction);
void setDispatchEventFunction(std::function<DispatchEventFunction> dispatchEventFunction);
void setReleaseEventTargetFunction(std::function<ReleaseEventTargetFunction> releaseEventTargetFunction);
void setReleaseEventHandlerFunction(std::function<ReleaseEventHandlerFunction> releaseEventHandlerFunction);
#pragma mark - Native-facing Interface
EventTarget createEventTarget(const InstanceHandle &instanceHandle) const;
void dispatchEvent(const EventTarget &eventTarget, const std::string &type, const folly::dynamic &payload) const;
void releaseEventTarget(const EventTarget &eventTarget) const;
#pragma mark - JavaScript/React-facing Interface
@ -75,7 +72,6 @@ private:
EventHandler eventHandler_;
std::function<CreateEventTargetFunction> createEventTargetFunction_;
std::function<DispatchEventFunction> dispatchEventFunction_;
std::function<ReleaseEventTargetFunction> releaseEventTargetFunction_;
std::function<ReleaseEventHandlerFunction> releaseEventHandlerFunction_;
};

View File

@ -30,16 +30,13 @@ EventTarget SchedulerEventDispatcher::createEventTarget(const InstanceHandle &in
return uiManager_->createEventTarget(instanceHandle);
}
void SchedulerEventDispatcher::releaseEventTarget(const EventTarget &eventTarget) const {
uiManager_->releaseEventTarget(eventTarget);
}
void SchedulerEventDispatcher::dispatchEvent(
const EventTarget &eventTarget,
const std::string &type,
const folly::dynamic &payload,
const EventPriority &priority
) const {
// TODO: Schedule the event based on priority.
uiManager_->dispatchEvent(eventTarget, normalizeEventType(type), payload);
}

View File

@ -33,8 +33,6 @@ public:
EventTarget createEventTarget(const InstanceHandle &instanceHandle) const override;
void releaseEventTarget(const EventTarget &eventTarget) const override;
void dispatchEvent(
const EventTarget &eventTarget,
const std::string &type,