Appcelerator Hyperloop vs. Plain Titanium Modules
Asked Answered
P

2

6

I've started playing around with Appcelerator Hyperloop. While it seems great to access native APIs from JS from day zero, it does raise a few questions about architecture of the platform and the performance.

Currently (AFAIK) a Titanium app has a main UI thread (that runs the native UI controllers) and a JS thread (that runs the JS logic). Each call from JS to Native is passed though the "Bridge" (which is the expansive operation in an app).

Also, Titanium API doesn't cover all the native API and abstracts as much as it can. But if new APIs are introduced it could take time for Appcelerator to implement those into the platform.

One of my favorite things about Titanium is the ability to extend it (using objective-c for iOS and java for Android) - allowing to use native APIs that are not covered by Titanium, and also developing a really native performance controls in case we need to do anything that's too "heavy" for JS. And, as mentioned it's developed 100% native for each platform.

Now that Appcelerator introduced Hyperloop I've done a simple test app and saw that Hyperloop is not translated into native code but just to normal JS code:

var UILabel = require('hyperloop/uikit/uilabel');
var label = new UILabel();
label.text = "HELLO WORLD!";
$.index.add(label); 

And another thing about it is that you have to run on the main thread.

So we basically have a few things come to mind here as far as Hyperloop architecture goes:

  1. We still have a bridge? if Hyperloop is JS that calls "special" Hyperloop require then we still have a bridge, that now not only acts as a bridge but also needs to do some sort of reflection (which is also an expansive operation)?
  2. Until now JS ran in it's own thread - so now running in a single main thread seems to be a potential source to more UI blocking operation.
  3. The old-fashioned modules were truly native (not including the bridge call) - so how do Hyperloop-enabled apps compare with those?

There isn't much documentation or articles about Hyperloop that explain the inner working yet - so if anyone has any answers have been trying apps with it could be very helpful.

Poetess answered 15/8, 2016 at 8:25 Comment(0)
C
7

Answering your questions straight-forward:

  1. There are no Kroll-Proxies involved anymore, since actual classes are being generated on runtime. This is done by using the hyperloop-metabase that does reflection (as you already said) to build an AST that grabs the actual signatures, types, classes, methods, properties, etc.
  2. We did not see any performance-issues with running on the main-thread for now. If you do so, please file a JIRA-ticket so we can investigate the use-case.
  3. The old-modules were "less native" then now, simply because they were all wrapped by the Kroll-proxy (by extending every view from TiUIView and every proxy from TiProxy / TiViewProxy. Hyperloop does not work with those, making the module-development much more faster by also allowing the developer to test his/her process live in their app without the need of packaging and referencing the module manually. Hyperloop modules are nothing else then CommonJS modules that are already used frequently across Alloy and other Ti-components.

I hope that gives you a quick overview on how Hyperloop works. If you have further questions, let us know!

Hans

Cryptograph answered 16/8, 2016 at 9:0 Comment(4)
Thanks. Indeed I see that the objects I get are KrollCallback and HyperloopClass. Could you further explain the architecture and what it means to run on the main thread? In old modules, let say I create a TableView with images and texts - what you are saying about wrapping the TableView with a TiView is true - but as far as the children object of that view (ImageView $ Label) - they are as native as an be - so are all the events you bind them to. Only what you bring back to JS crosses the bridge - so isn't it more performant than doing reflection?Poetess
Hey there! I did an own answer for this, since comments can only have 600 chars.Yuriyuria
@HansKnoechel Is it possible to create a Hyperloop module? I saw your proposed spec and am wondering how progress/planning is for this. Obviously people want plug and play modules not just creating custom Hyperloop business logic everytime.Pase
@Pase Basically, it's just a CommonJS module with an additional project structure to manage the assets correctly. I'm not sure about the exact timeframe of realising that, but it's definitely something that should be added to make it even more easier to create reusable components, especially from the CLI and Studio directly.Yuriyuria
C
1

(As a detailed answer to the above comment)

So let's say you have a tableview in iOS. The native class is UITableView and the Titanium-API is Ti.UI.TableView / Ti.UI.ListView.

While the ListView already provides a huge performance-boost compared to the TableView by abstracting the Child-API usage to templates, those child-API's (Ti.UI.Label, Ti.UI.ImageView, ...) are still custom classes that are wrapped and provide custom logic (!) e.g. keeping track of it's parent-references, internal data-structures and locks to jump between the threads.

If you now check the Hyperloop example of a native UITableView, you access the native API's directly, so no proxy behind it needs to manage sections, templates, items etc. Of course we deliver that API through a kroll proxy in order to display it in Titanium, but you don't "jump between the bridge" with every call you make from the SDK.

The easiest way to see that is to actually run some bigger example like the tableview, collectionview and view-animation. If you do a fast scroll through these, you already feel the performance boost compared to "classic" Titanium API's, simply because the only communication between your proxy and (like a Ti.UI.Window you want to add it to) is the .add() to receive the native API of the type HyperloopClass.

Finally, of course it still makes sense to use Ti.UI.ListView for example, because it comes with the builtin utilities that Titanium devs love (events, easy configuration and layout-handling). But thats also where the benefit of Hyperloop comes along, by allowing the developer to access those API's him-/herself.

I hope that helps a bit more to understand it.

Cryptograph answered 17/8, 2016 at 15:53 Comment(4)
Thanks. I think I was misunderstood in my question that lead to this answer. What I meant is that if I create a "classic" module and I create a TableView (or any view for that matter) the child elements and the events of the container view (which is the only one who's being wrapped around TiUIView) are all native, not wrapped, not reflected, elements. So in theory they should yield better performance.Poetess
Gotcha. Time for some benchmarking-tests :-) Although I still think that any interaction with the native module would go through more bridges again so Hyperloop would "win". But that actually needs tests.Yuriyuria
I think it really depends on the module and what is the designed communication between the module and the JS logic. Lets say for an example we're building a gallery - the module loads the images, and respond to click events, and selecting images - on all module native side - only when selected images should go back to JS then it crosses the bridge. So all interaction will be native except the return result - again that all depends per module definition.Poetess
I think the best way to use Hyperloop is to still create modular libraries in Native code then expose them via Hyperloop. The idea of requiring all the Java classes in JS then creating the class I want seems more tedious and error prone than just using a .aar for example. I see this is possible and am glad.Pase

© 2022 - 2024 — McMap. All rights reserved.