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

Refactor reference expression impl and allow dynamic ref depths #3220

Merged
merged 2 commits into from
Mar 29, 2018

Conversation

evs-chris
Copy link
Contributor

Description:

This tosses most of the old ReferenceExpressionProxy code and just swaps in a specialized LinkModel subclass. In addition to being considerably smaller, this also allows for a minor feature addition I've been wanting for a while: dynamic depth reference expressions. "Ooooh", you say. "That sounds lovely!". And indeed it is, because you can have fully bindable dynamic references with ~/[someKeypathArray], and the array will be expanded inline when stringing together the keypath. Multiple keys are still possible, and will behave how you'd expect when mixing arrays and strings/numbers.

Fixes the following issues:

A little bloat.

Is breaking:

Don't think so... at least all of the tests turn green.

@evs-chris evs-chris merged commit 10f84f7 into dev Mar 29, 2018
@evs-chris evs-chris deleted the refproxy branch March 29, 2018 20:44
@PaulMaly
Copy link

@evs-chris How about performance? Seems Edge already less performant than 0.9, isn't it?

@evs-chris
Copy link
Contributor Author

I haven't run any benchmarks, but this is as performant as component mappings because they now use the same code. Most of the performance pain in ractive tends to come from DOM manipulation and GC pauses. I haven't done any benchmarks of late, but I also haven't noticed an appreciable slowdown in any of my apps on edge. As long as you don't try to render too many DOM nodes at once (paginate, leave tree nodes collapsed until needed, etc), ractive performance tends to be be very good.

Is there anything in particular that you have seen slow down?

@PaulMaly
Copy link

@evs-chris Nothing concrete, but soon I'll start new Smart TV app and I'm thinking of which tool to choose for this. Smart TV is a very sensitive to performance issues and memory usage.

Regarding benchmarks, I usually trust to this one: https://rawgit.com/krausest/js-framework-benchmark/master/webdriver-ts-results/table.html

And seems Ractive doesn't have very good metrics there. What do you think about it?

@evs-chris
Copy link
Contributor Author

Ah, yes. That's pretty much the standard comparison benchmark, but it's not exactly entirely objective any more. Lots of frameworks have put in mirco-optimzations that target that benchmark specifically, even though the worst case (10k rows) is not something you would want to do in a normal app. That said, ractive doesn't exactly do badly in that benchmark. 50% overhead vs hand optimized js is not too bad in my opinion, and 30% overhead vs the framework I consider to be the slimmest (svelte) is not awful either. The startup time for ractive is actually significantly exaggerated there, because pre-parsed templates are not used. Also note that that edge version is probably edge just prior to 0.9.0, or at least it was when I added it prior to the 0.9 release and someone updating the 0.8 version to 0.9. I'm not sure what's up with the svelte keyed benchmark right now either.

For something with really tight memory requirements, I would not recommend ractive (or js in general, but that's neither here nor there). If the data changes wildly, meaning that large chunks of model come and go in different keypaths, ractive doesn't gc its model, so whatever is the maximum size of all of the data is the size that it will retain in supporting model structures.

That said, ractive is really good at applying updates, especially inline without shuffling.

@PaulMaly
Copy link

@evs-chris Thanks, Chris! I'm very interested your opinion! Maybe you able to provide some recommendations how can I make Ractive performant as it possible? Maybe you've some tips and tricks?

@evs-chris
Copy link
Contributor Author

Here's my list of things to do or not do if performance is a concern:

  1. Most importantly, pre-parse your templates! This requires a build step, but it really does make a difference in speed. You lose a little bit of space because the parsed templates are slightly larger than the template text in most cases, but it also lets you use the runtime version of ractive, which saves ~30k minified off of the top.
  2. Components are great, but don't use them unnecessarily. Components have a pretty significant overhead, so if possible, avoid using them in iterative sections. This is one of the reasons that macro partials were introduced - you get a lot of the benefits of a component without the extra overhead, with the only significant downsides being no access to extra methods on the macro and no separate eventing system.
  3. Don't render giant structures directly to the DOM. If you have a list of 100 items to render, that's probably fine, though depending on their size, your users would probably still thank you to paginate that and give them some sort of filtering. Rendering a large tree with all nodes already expanded is probably not something you're going to want to navigate either.
  4. Use lazy input bindings wherever possible when the bound value affects other parts of the template. For instance, when having a filter input adjust the list of items displayed below it, set lazy to a number so that every keystroke doesn't immediately hit the DOM.
  5. For things like tabs and accordions, go ahead and render everything to the DOM ahead of time with something like display: none for the bits that shouldn't be visible. This makes switching faster and you don't run into weird things like components on hidden sections losing their local state when they are torn down and recreated as they are hidden and shown again.
  6. Use CSS transitions when you can, as opposed to using animate. animate is still super handy for handling things that CSS transitions can't, but a CSS transition or a ractive transition plugin that uses CSS transitions under the hood is going to be more performant in most of the cases that they can be used.

There're probably some other things you can do to improve performance, but after the third one in this list, they're usually either very case specific or bordering on a micro-optimization e.g. saving 1ms on a 3ms action is often not worth the extra effort and complexity. While sticking with the top 3 items in this list, I have yet to run across a serious performance issue in any of my ractive apps for any version from 0.7 on.

@PaulMaly
Copy link

@evs-chris Thanks! Seems, I use most of these things, except "runtime version". I didn't know about this opportunity. How can I get it via npm?

@evs-chris
Copy link
Contributor Author

If you're bundling ractive via npm + an es bundler, import Ractive from 'ractive/runtime';. If you're just dropping the global on the page for cacheability, I'd recommend https://cdn.jsdelivr.net/npm/ractive@edge/runtime.min.js (or whatever version you're targeting).

Note that the whole parser is missing from the runtime version, so if you try to use a computed in string form or any stringy templates, you'll get an exception.

@PaulMaly
Copy link

Great! Thanks, I'll try that!

@evs-chris evs-chris added this to the 0.10 milestone Apr 3, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants