Reviewing Ember and wondering about performance issue

I branched and created an ember-cli version to better analyze the performance issue and give you a solid answer. That branch is here: GitHub - runspired/lab16_emberjs at ember-cli-version

It serves as a relatively good example of a performance trap using {{#each}} that a lot of ember beginners fall into. I’d argue there should be docs letting you know how to avoid this pitfall, but the upcoming Glimmer diffing will render most of this performance pitfall mute, and if I get MagicCollectionView finished, that will solve the other portion of this as well.

##Rerendering Stats for {{#each}}

  • original code: ~380ms
  • modified code: <1ms
  • modified code when images are inserted: ~10ms (could be made faster, the image insertion method here is pretty dirty)

Eesh, that’s a big difference. What went wrong?

Before my mods, each keystroke completely rebuilt the array, so my first step was to ensure that the underlying array instance wasn’t destroyed. Most of the time, that’s all that’s needed to ensure solid performance of the {{#each}} helper.

This change helped, but it only reduced the average by ~15ms. Ouch, not the silver bullet I was hoping for. The reason was fairly clear though, I was clearing the old array using array.length = 0 and inserting brand new rows with the new data. Your rows change every time, so each of the list items will need to be re-rendered anyway.

You might already be able to guess where this is going, but the next step was to re-use the same object instances for rows. This prevents Ember from needing to teardown the component and it’s HTML and generate a new one. And yes, before it needed to build both a new component and new DOM, so your performance hit is a double whammy.

I moved what had been a series of computed properties on your table-row component to being performed by a helper function in your route controller, and passed the existing object for that row index into the helper to reuse it.

At the end of the day, there is no substitute for a good algorithm, but what you bumped into here is a very widely known performance issue for Ember, which (awesomely) will largely disappear in ~12 weeks time without everyone needing to learn to optimize their {{#each}} helpers in this way.

###Glimmer Preview

###One of many demonstrations of this particular failure

As an aside, before you use Florence’s talk to judge Ember’s performance to harshly, it should be noted, that in Ryan Florence’s demo code, he did not try to optimize his rows in the manner I show here, nor did his code make use of Ember.run.schedule('afterRender') which would have helped him a lot in this use case, and he used a version with a known performance regression, and he simply doesn’t focus the window to make the claim that ember doesn’t even get to the mouseovers. In short, there’s a lot of issues with that talk, but the main premise does hold, it’s easy to bump into this problem.

5 Likes