Skip to content

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

@ide

Description

@ide
Contributor

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

Activity

ide

ide commented on Apr 6, 2015

@ide
ContributorAuthor

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

sophiebits commented on Apr 6, 2015

@sophiebits
Contributor

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

sophiebits

sophiebits commented on Apr 6, 2015

@sophiebits
Contributor

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

nicklockwood

nicklockwood commented on Apr 6, 2015

@nicklockwood
Contributor

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

nicklockwood

nicklockwood commented on Apr 6, 2015

@nicklockwood
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

ide commented on Apr 7, 2015

@ide
ContributorAuthor

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

nicklockwood commented on Apr 7, 2015

@nicklockwood
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

ide commented on Apr 7, 2015

@ide
ContributorAuthor

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

ide commented on May 29, 2015

@ide
ContributorAuthor

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

added a commit that references this issue on Aug 5, 2015
locked as resolved and limited conversation to collaborators on May 29, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Efficiently load RCTBridgeModule classes and allow lazy, background-thread initialization · Issue #69 · facebook/react-native