Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Efficiently load RCTBridgeModule classes and allow lazy, background-thread initialization #69

Labels
Resolution: Locked This issue was locked by the bot.

Comments

@ide
Copy link
Contributor

ide commented Feb 14, 2015

RCTBridgeModuleClasses currently scans all(!) of the classes available at runtime to find which are modules. I believe a more explicit approach where modules are loaded only when needed is better for a couple of reasons:

  • No need to loop through all iOS classes
  • Fewer side effects from implicitly invoking +[load] and +[initialize] on otherwise-unused classes
  • Modules can be loaded on the JavaScript thread instead of the main thread -- some of the aforementioned side-effect methods in unused classes expect to run on the main thread
  • Modules can be lazily loaded as needed
@ide
Copy link
Contributor Author

ide commented Apr 6, 2015

Working on this now. I expect a good performance win and a more encapsulated API (replacing a lot of globals) to come out of this.

@sophiebits
Copy link
Contributor

I think @nicklockwood and @a2 are planning to get this in tomorrow actually.

@sophiebits
Copy link
Contributor

Or at least, some version of it that removes the class-crawling.

@nicklockwood
Copy link
Contributor

We are. I'm interested to hear your thoughts on how to approach it though.

@nicklockwood
Copy link
Contributor

Our initial implementation is just going to replace the class crawling with an alternative automatic registration mechanism that uses mach-O data headers (much the same as how methods are currently registered with RCT_EXPORT).

This means we get to keep the automatic module registration, but get rid of the need to scan every class in the whole app. Automatic registration has a lot of advantages, and you can already opt-out of it if necessary by returning nil from init (or, in the new system, by not adding the RCT_EXPORT_MODULE macro).

Lazy init is something I've been thinking about, but there are certain cases where you want your module to be initialized immediately - for example if it broadcasts notifications, or needs to register some constants - so it's not simply a case of waiting until the first time it's called.

@ide
Copy link
Contributor Author

ide commented Apr 7, 2015

OK. Thanks for letting me know.

One goal of mine to be able to disable automatic module registration so that I can provide different module implementations (or exclude modules) for different root views, so I'm looking forward to the new system.

I had a module loader that handled the module class <-> ID <-> name mapping and could generate the "remote module" and "local module" configs. This let me delete most of the static functions and variables in RCTBridge.m, which I wanted so that two different root views could use two separate sets of remote & local modules.

Re: lazy init -- currently I'm thinking that the number of modules should be fairly small (under 1000) it actually seems fine to initialize all modules up front and the ones that do heavy work can implement some kind of lazy initialization on their own.

@nicklockwood
Copy link
Contributor

As you say, there shouldn't be much overhead to having extra modules initialised that you aren't using, so our current recommendation if you want different modules in two different root views is simply to load all of them in both - especially since we've now set it up so root views can share the same bridge (which is a much bigger resource saving, as it means there's only only JavaScript context running).

It's also possible to override built-in modules with your own by injecting another module with the same moduleName, so I think we've covered cases like test mocking, or providing your own versions of (for example) XHP, that use your existing network stack (we do this for our internal apps).

Please do let us know if you have use cases we aren't handling yet though - and if you want to share your alternative architecture idea as an "RFC" pull request, then please do that too - we might still incorporate some of the ideas :-)

@ide
Copy link
Contributor Author

ide commented Apr 7, 2015

One feature I'd like is the ability to enable or disable autoloading for specific bridges. For example one bridge may autoload all linked modules while another bridge would only have modules provided to it. I could work on a PR when you guys complete the new module loader but it would be great if the code you're currently writing anticipated this feature or even implemented it.

I had a diff about 1/3 complete where the only moderately interesting part is being able to skip autoloading if the module provider is specified: ide@b8271e9#diff-e15318f48b6447f2d9936c5e047d882fR509

@ide
Copy link
Contributor Author

ide commented May 29, 2015

The new module system from awhile back addressed most of what this issue was about. Closing out.

@ide ide closed this as completed May 29, 2015
harrykiselev pushed a commit to harrykiselev/react-native that referenced this issue Aug 5, 2015
Fix erroneous file name reference in examples/flux-todomvc/README.md
@facebook facebook locked as resolved and limited conversation to collaborators May 29, 2018
@react-native-bot react-native-bot added the Resolution: Locked This issue was locked by the bot. label Jul 23, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.