5

I have a so called chat view that basically consists of a repeat.for that loops over all the messages and renders the message views using <compose>.

The problem is that it becomes quite slow once the message count exceeds 50 and the user navigates between chats (which triggers the repeat.for update, as I replace the dataset in the VM).

I feel like I am doing something wrong in regards of handling a view like this. Can I get some input regarding other alternatives?

I have tried UI virtualization, but unfortunately the current plugin does not offer support for features that I require (variable height items, bottom-up alignment).

I have also done quite a bit of optimizations regarding bindings, most are one-time and updates to the dataset are debounced. But this did not improve things, as the main bottleneck is the initial load (binding the views the first time).

Thanks!

Example of current approach:

<li repeat.for="message of chat.messages">
  <compose  view-model.bind="getMessageViewFromMessage(message) & oneTime"
            model.bind="message & oneTime"
            containerless>
  </compose>
</li>
Tarps
  • 1,928
  • 1
  • 11
  • 27
  • Can you define "quite slow"? – mgiesa Nov 02 '16 at 20:21
  • Definitely. The initial view for a chat is 50 messages (the first page). It takes about 600-900ms to display that, during which time the UI thread is frozen. And this is on the Chrome's V8 JavaScript engine. – Tarps Nov 02 '16 at 20:31
  • Since a lot of it is just plain HTML and does not actually require a lot of bindings (besides audio and media messages), then I'd like to know what options might I have to speed things up. Current course of action is to turn plain text messages into static HTML, by binding to innerHTML. But that will not work on audio and media messages, since they also require some bindings (like `click` delegation and references to `audio` objects). – Tarps Nov 02 '16 at 20:38

2 Answers2

3

I think you need to consider not using <compose> at all for this. Is there a reason you need <compose>? When you think about it, the <compose element has to re-run through the same view instantiation/binding logic Aurelia does for everything else, every time a message is displayed.

I would personally create a HTML partial with some bindable properties and inside of the loop, reference it. So you might have chat-message.html and then display it like this:

<li repeat.for="message of messages">
    <chat-message message.bind="message"></chat-message>
</li>

Where possible and in most cases it should be, avoid dynamic composition for potentially large sets of repeated items.

Dwayne Charrington
  • 6,524
  • 7
  • 41
  • 63
  • Hey. I used `` because I have a lot of different views (5 different types). For example text, audio end media (image/video). Would it be faster if I created five different dynamic views, but then bound them together and selected the correct one using `if.bind`? (`if.bind="message.type === 'text'"` etc) – Tarps Nov 03 '16 at 07:04
  • Hey Dwayne. I tested it out just now and I can confirm that is indeed faster, even though it seems a bit confusing to me. As I would have expected the `` approach to be faster. – Tarps Nov 03 '16 at 07:44
  • That's awesome Travo. I think in your case where you could potentially have many items being rendered one after another you would see some side-effects because of the implicit environment that `` carries with it. To answer your question you could use an if.bind or you could pass the type through to a generic element and then handle it in there like a switch/case statement kind of thing. – Dwayne Charrington Nov 04 '16 at 04:57
  • Amazing! I'm using Aurelia with phonegap. Moved from 'compose' to 'if.bind' and rendering time decreased from 6 seconds to less than 2. Thanks! – Alon Bar Jul 16 '17 at 20:14
  • Wow @AlonBar that is a significant reduction in rendering time. – Dwayne Charrington Jul 16 '17 at 23:22
  • I guess you should avoid using compose for more than a few elements in a page. My case is similar to Travo's as I'm rendering around 100 elements. Even though, I was shocked by the significant perormance boost. – Alon Bar Jul 17 '17 at 06:16
1

You should check out the aurelia-ui-virtualization library. Once you load it, you can replace repeat.for with virtual-repeat.for in places like this and you'll get a virtualized repeater that will help improve perf with this type of situation.

Ashley Grant
  • 10,879
  • 24
  • 36
  • I mentioned in the original post that it did not fit my criterias, due to two reasons. Thanks though. – Tarps Nov 02 '16 at 18:59
  • Ah, I see that now. I would recommend submitting a feature request to that repo and hopefully we'll be able to iterate on it to support this. – Ashley Grant Nov 02 '16 at 20:39