Cache batched bridge methods and provide better error messages when calling functions without bridge config

Summary: Maybe a slight perf improvement. Also helps get rid of the 'ReferenceError: __fbBatchedBridge' error in favor of a more explicit "you're calling JS functions before the bundle is loaded"

Differential Revision: D3142966

fb-gh-sync-id: 6a50efe7d1634248107c8c95a3e014cb263a9ca5
fbshipit-source-id: 6a50efe7d1634248107c8c95a3e014cb263a9ca5
This commit is contained in:
Andy Street 2016-04-11 15:04:36 -07:00 committed by Facebook Github Bot 8
parent 8ef551174b
commit c24fae9544
4 changed files with 58 additions and 11 deletions

View File

@ -9,6 +9,7 @@
#include <string>
#include <glog/logging.h>
#include <folly/json.h>
#include <folly/Memory.h>
#include <folly/String.h>
#include <sys/time.h>
@ -199,6 +200,9 @@ void JSCExecutor::terminateOnJSVMThread() {
terminateOwnedWebWorker(workerId);
}
m_batchedBridge.reset();
m_flushedQueueObj.reset();
s_globalContextRefToJSCExecutor.erase(m_context);
JSGlobalContextRelease(m_context);
m_context = nullptr;
@ -257,28 +261,62 @@ void JSCExecutor::loadApplicationUnbundle(
loadApplicationScript(startupCode, sourceURL);
}
bool JSCExecutor::ensureBatchedBridgeObject() {
if (m_batchedBridge) {
return true;
}
Value batchedBridgeValue = Object::getGlobalObject(m_context).getProperty("__fbBatchedBridge");
if (batchedBridgeValue.isUndefined()) {
return false;
}
m_batchedBridge = folly::make_unique<Object>(batchedBridgeValue.asObject());
m_flushedQueueObj = folly::make_unique<Object>(m_batchedBridge->getProperty("flushedQueue").asObject());
return true;
}
void JSCExecutor::flush() {
// TODO: Make this a first class function instead of evaling. #9317773
std::string calls = executeJSCallWithJSC(m_context, "flushedQueue", std::vector<folly::dynamic>());
#ifdef WITH_FBSYSTRACE
FbSystraceSection s(
TRACE_TAG_REACT_CXX_BRIDGE, "JSCExecutor.flush");
#endif
if (!ensureBatchedBridgeObject()) {
throwJSExecutionException(
"Couldn't get the native call queue: bridge configuration isn't available. This shouldn't be possible. Congratulations.");
}
std::string calls = m_flushedQueueObj->callAsFunction().toJSONString();
m_bridge->callNativeModules(*this, calls, true);
}
void JSCExecutor::callFunction(const std::string& moduleId, const std::string& methodId, const folly::dynamic& arguments) {
// TODO: Make this a first class function instead of evaling. #9317773
std::vector<folly::dynamic> call{
moduleId,
methodId,
std::move(arguments),
if (!ensureBatchedBridgeObject()) {
throwJSExecutionException(
"Couldn't call JS module %s, method %s: bridge configuration isn't available. This "
"probably means you're calling a JS module method before bridge setup has completed or without a JS bundle loaded.",
moduleId.c_str(),
methodId.c_str());
}
std::vector<folly::dynamic> call {
moduleId,
methodId,
std::move(arguments),
};
std::string calls = executeJSCallWithJSC(m_context, "callFunctionReturnFlushedQueue", std::move(call));
m_bridge->callNativeModules(*this, calls, true);
}
void JSCExecutor::invokeCallback(const double callbackId, const folly::dynamic& arguments) {
// TODO: Make this a first class function instead of evaling. #9317773
std::vector<folly::dynamic> call{
(double) callbackId,
std::move(arguments)
if (!ensureBatchedBridgeObject()) {
throwJSExecutionException(
"Couldn't invoke JS callback %d: bridge configuration isn't available. This shouldn't be possible. Congratulations.", (int) callbackId);
}
std::vector<folly::dynamic> call {
(double) callbackId,
std::move(arguments)
};
std::string calls = executeJSCallWithJSC(m_context, "invokeCallbackAndReturnFlushedQueue", std::move(call));
m_bridge->callNativeModules(*this, calls, true);

View File

@ -88,6 +88,8 @@ private:
std::shared_ptr<MessageQueueThread> m_messageQueueThread;
std::unique_ptr<JSModulesUnbundle> m_unbundle;
folly::dynamic m_jscConfig;
std::unique_ptr<Object> m_batchedBridge;
std::unique_ptr<Object> m_flushedQueueObj;
/**
* WebWorker constructor. Must be invoked from thread this Executor will run on.
@ -105,6 +107,7 @@ private:
void flush();
void flushQueueImmediate(std::string queueJSON);
void loadModule(uint32_t moduleId);
bool ensureBatchedBridgeObject();
int addWebWorker(const std::string& script, JSValueRef workerRef, JSValueRef globalObjRef);
void postMessageToOwnedWebWorker(int worker, JSValueRef message, JSValueRef *exn);

View File

@ -69,6 +69,11 @@ Value Object::callAsFunction(int nArgs, JSValueRef args[]) {
return Value(m_context, result);
}
Value Object::callAsFunction() {
JSValueRef args[0];
return callAsFunction(0, args);
}
Value Object::getProperty(const String& propName) const {
JSValueRef exn;
JSValueRef property = JSObjectGetProperty(m_context, m_obj, propName, &exn);

View File

@ -125,6 +125,7 @@ public:
}
Value callAsFunction(int nArgs, JSValueRef args[]);
Value callAsFunction();
Value getProperty(const String& propName) const;
Value getProperty(const char *propName) const;