Summary: This leaves no optional methods on `RCTJavaScriptExecutor`, which is certainly a good thing.
Reviewed By: majak
Differential Revision: D3518915
fbshipit-source-id: e606b9076c3299f81a225a181ea244148a1832cb
Summary:
After cleaning up JS SourceMap code, these native methods are not needed anymore.
On iOS it saves another 30+ Mb during development.
Reviewed By: javache, astreet
Differential Revision: D3348975
fbshipit-source-id: a68ae9b00b4dbaa374b421029ae676fc69ae5a75
Summary:
As per https://twitter.com/olebegemann/status/738656134731599872, our use of "main thread" to mean "main queue" seems to be unsafe.
This diff replaces the `NSThread.isMainQueue` checks with dispatch_get_specific(), which is the recommended approach.
I've also replaced all use of "MainThread" terminology with "MainQueue", and taken the opportunity to deprecate the "sync" param of `RCTExecuteOnMainThread()`, which, while we do still use it in a few places, is incredibly unsafe and shouldn't be encouraged.
Reviewed By: javache
Differential Revision: D3384910
fbshipit-source-id: ea7c216013372267b82eb25a38db5eb4cd46a089
Summary:
This is a solution for the problem I raised in https://www.facebook.com/groups/react.native.community/permalink/768218933313687/
I've added a new native base class, `RCTEventEmitter` as well as an equivalent JS class/module `NativeEventEmitter` (RCTEventEmitter.js and EventEmitter.js were taken already).
Instead of arbitrary modules sending events via `bridge.eventDispatcher`, the idea is that any module that sends events should now subclass `RCTEventEmitter`, and provide an equivalent JS module that subclasses `NativeEventEmitter`.
JS code that wants to observe the events should now observe it via the specific JS module rather than via `RCTDeviceEventEmitter` directly. e.g. to observer a keyboard event, instead of writing:
const RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
RCTDeviceEventEmitter.addListener('keyboardWillShow', (event) => { ... });
You'd now write:
const Keyboard = require('Keyboard');
Keyboard.addListener('keyboardWillShow', (event) => { ... });
Within a component, you can also use the `Subscribable.Mixin` as you would previously, but instead of:
this.addListenerOn(RCTDeviceEventEmitter, 'keyboardWillShow', ...);
Write:
this.addListenerOn(Keyboard, 'keyboardWillShow', ...);
This approach allows the native `RCTKeyboardObserver` module to be created lazily the first time a listener is added, and to stop sending events when the last listener is removed. It also allows us to validate that the event strings being observed and omitted match the supported events for that module.
As a proof-of-concept, I've converted the `RCTStatusBarManager` and `RCTKeyboardObserver` modules to use the new system. I'll convert the rest in a follow up diff.
For now, the new `NativeEventEmitter` JS module wraps the `RCTDeviceEventEmitter` JS module, and just uses the native `RCTEventEmitter` module for bookkeeping. This allows for full backwards compatibility (code that is observing the event via `RCTDeviceEventEmitter` instead of the specific module will still work as expected, albeit with a warning). Once all legacy calls have been removed, this could be refactored to something more elegant internally, whilst maintaining the same public interface.
Note: currently, all device events still share a single global namespace, since they're really all registered on the same emitter instance internally. We should move away from that as soon as possible because it's not intuitive and will likely lead to strange bugs if people add generic events such as "onChange" or "onError" to their modules (which is common practice for components, where it's not a problem).
Reviewed By: javache
Differential Revision: D3269966
fbshipit-source-id: 1412daba850cd373020e1086673ba38ef9193050
Summary:
Modules which call JS methods directly, or use `sendDeviceEventWithName:`, can trigger effects in JS without ever being referenced from the JS code. This breaks some assumptions in my earlier diff about when modules can be lazily loaded.
Pending a better solution, I've put explicit `init` methods in these modules to ensure they are eagerly initialized (the downside to this is that they'll still be initialized even if they are never used).
Reviewed By: javache
Differential Revision: D3258232
fb-gh-sync-id: f925bc2e5339c1fbfcc244d4613062c5ab848fc2
fbshipit-source-id: f925bc2e5339c1fbfcc244d4613062c5ab848fc2
Summary:
Now that we support initializing the bridge off the main thread, some of the assumptions in the bridge setup process are no longer safe.
In particular we were assuming that the JS executor and injected modules could always be synchronously initialized within bridge init, but that is only safe if those modules don't need to be set up on the main thread.
The setup for those modules was sync-dispatching to the main thread if bridge init happened on a background thread, and this lead to a deadlock under certain circumstances.
Reviewed By: javache
Differential Revision: D3224162
fb-gh-sync-id: 7319b70f541a46ef932cfe4f776e7e192f3ce1e8
fbshipit-source-id: 7319b70f541a46ef932cfe4f776e7e192f3ce1e8
Summary:When JSC throws an error on startup (e.g. a SyntaxError) or when invoking a method that is not caught by RCTExceptionsManager, we previously just reported is a native error, with a (useless) native stack trace in the redbox. This changes that behaviour to report a JS stacktrace.
The same issue was previously reported here: https://github.com/facebook/react-native/pull/5677
Reviewed By: majak
Differential Revision: D3037387
fb-gh-sync-id: 06f8333e0eb50dcef0b26284754262301b8a5f08
fbshipit-source-id: 06f8333e0eb50dcef0b26284754262301b8a5f08
Summary:The 200ms timeout was causing resource issues and causing a lot of overhead when you're not running the devtools, since it will basically create a new socket every 200ms.
Also clean up the way we do logging so it's completely compiled out in prod, and standardize all the names we use for threading to lowercase react.
Reviewed By: frantic
Differential Revision: D3115975
fb-gh-sync-id: e6e51c0621d8e9fc4eadb864acd678b8b5d322a1
fbshipit-source-id: e6e51c0621d8e9fc4eadb864acd678b8b5d322a1
Summary:Interface to `RCTBatchedBridge` was being declared in two different implementation files. This is suboptimal, since it makes it hard to mock that class in a test.
So I've merged and moved these two definitions in `RCTBridge+Private.h`, so it's still obvious it's a private class, but can be included if you really need it.
Reviewed By: javache
Differential Revision: D3126135
fb-gh-sync-id: 173e4c5c2925be387b92deb7f99952ca7bf28588
fbshipit-source-id: 173e4c5c2925be387b92deb7f99952ca7bf28588
Summary:`flowIDMap` lives on the bridge to map from the IDs used for the flow events in
JS and the ones generated by `RCTProfile` in the native side.
It was being accessed from multiple threads (the various modules' queues in the
bridge and the JS thread), so we lock before touching it.
Reviewed By: javache
Differential Revision: D3102745
fb-gh-sync-id: 93d012d124e8b5d1a390c10a98ef5e3a068ccf63
fbshipit-source-id: 93d012d124e8b5d1a390c10a98ef5e3a068ccf63
Summary: This diff adds support for initializing the bridge on an arbitrary thread. This is helpful if you want to defer bridge creation, or prevent it from delaying your app startup.
Reviewed By: javache
Differential Revision: D2965725
fb-gh-sync-id: 8065fa89e850031c72ee4427351300986985e9de
shipit-source-id: 8065fa89e850031c72ee4427351300986985e9de
Summary:Initializing native modules can block the main thread for tens of milliseconds when it starts up, making it difficult to instantiate the bridge on demand without causing a performance blip.
This diff splits up the initialization of modules so that - although they still happen on the main thread - they don't block the thread continuously.
Reviewed By: javache
Differential Revision: D2965438
fb-gh-sync-id: 38c9c9d281e4672b5874d68b57d4c60d1d268344
shipit-source-id: 38c9c9d281e4672b5874d68b57d4c60d1d268344
Summary: The module initialization process is complex and full of race conditions. This diff adds a set of unit tests that verify that modules setup happens in the correct order, and enforces all the various conditions for main/background init.
Reviewed By: javache
Differential Revision: D2994145
fb-gh-sync-id: 92ea84508cdeeb280ff0fb9e9b2dffa8dbc37e66
shipit-source-id: 92ea84508cdeeb280ff0fb9e9b2dffa8dbc37e66
Summary:
public
Lazy export of module constants required a sync dispatch to the main thread, which was deadlocking in some of our projects.
This moves the constants export to the initial bridge init, which may slightly increase initial startup time, but avoids the deadlock.
Reviewed By: javache
Differential Revision: D2911295
fb-gh-sync-id: 0d14a629ac4fc7ee21acd293c09595c18232659b
shipit-source-id: 0d14a629ac4fc7ee21acd293c09595c18232659b
Summary:
public
Expose JS hooks to create flow events in systrace (the nice arrows to show async work flow) +
add support to the showing all the work enqueued from the JS thread as added in D2743733
Depends on D2743733
Reviewed By: jspahrsummers
Differential Revision: D2815293
fb-gh-sync-id: 4278f61a67a6e78cf2704bacce34b1389328c6df
Summary:
This solves https://github.com/facebook/react-native/issues/5090. Since 5b4e873c68 we had better reporting for when calls from native to JS fail. When trying to load an invalid bundle, this would now cause a stackoverflow, since RCTFatal would schedule a JS call to log, which would RCTFatal, which would ...
By invalidating the jsExecutor immediately after loading fails, we prevent any more attempts to log. We can't invalidate the whole bridge at this point since we still need the redbox module to actually display the error.
public
Reviewed By: majak
Differential Revision: D2834251
fb-gh-sync-id: a3e2ad425e40560beae4d3eacb93f66ace5341bf
Summary:
public
Fixed a potential deadlock issue if code attempted to access a module via [bridge moduleForName/Class:] while it was being initialized.
Reviewed By: lry
Differential Revision: D2807827
fb-gh-sync-id: 58cafe9b92c094dde632d17245fb9b342a0fe9e0
Summary:
public
Android implement ViewManager methods via a dispatch method on UIManager, whereas iOS implements them by exposing the methods on the view manager modules directly.
This diff polyfills Android's implementation on top of the iOS implementation, allowing the same JS API to be used for both.
Reviewed By: javache
Differential Revision: D2803020
fb-gh-sync-id: 0da0544e593dc936467d16ce957a77f7ca41355b
Summary:
public
The logic inside RCTBatchedBridge contained some race conditions that would occasionally cause an error if modules were loaded in the wrong order. This improves that logic and makes it safer by adding a lock to prevent concurrency.
Reviewed By: jspahrsummers
Differential Revision: D2802930
fb-gh-sync-id: d1ad25fa578649363dcaac029cb24dc3a453ae67
Summary:
public
Expose JS hooks to create flow events in systrace (the nice arrows to show async work flow) +
add support to the showing all the work enqueued from the JS thread as added in D2743733
Depends on D2743733
Reviewed By: jspahrsummers
Differential Revision: D2773664
fb-gh-sync-id: 4a8854b17b4741b882f5f2cc425e4237a5e4b3eb