WinJS 2.0 Listview tips
As I wrote in my previous post WinJS team greatfully optimized Template rendering. There was also a great post from Kraig Brockschmidt about rendering optimization technics and the most advanced and fastest option was to use two phased item rendering:
- 1st phase was to show some item content asap - e.g. in case of contact list it's just person's name
That's very usefull whe scrolling the listview so that the user knows what position he/she is at.
- 2nd phase is started when the user stopped scrolling the listview and the content should be shown completely. It's recommended to split this into at least 2 subphases, too
- Loading all data and activate/initialize binding
- batch loading images (i.e. persons' avatars in case of contacts) and load them in one stream later on
Great news is that the main phases are implemented in new item rendering by default. How?
Item rendering details
- set option on the template: debugBreakOnRender:true
- set the option globally for all templates: WinJS.Binding.Template._debugBreakOnRender
The template definition code (scroll to the right to see the options) is:
Looking the generated code is also great for self-learning and understanding the internal rendering code.
In the sample you can see three important things:
- renderItem return an object with two fields, both promises (lines 92 ~ 95):
- element - this is the first phase of rendering phase
- renderComplete - this contains the second rendering phase
- the template was turned into the HTML string and that some parts are directly replaced in the first rendering phase (lines: 59 ~ 62)
- line 31 contains a code which breaks the IDE to stop so that we can debug the rendering code.
During the first rendering phase, the HTML string for the item is built on concatenating the static template definition strings and escaped data and then it's inserted into DOM. The string concatenation is quite expensive operation. So let's see what we can do with it and concatenate only really necessary fields, i.e. name only.
There is so called WinJS.Binding._TemplateCompiler class which contains a method optimize. This method optimizes the standard binding declarations (bindings exposed on WinJS.Binding namespace). I recommend you to look at the source code of this method in base.js.
The standard binding declaration which binds to the common element attributes (e.g. innerText: name) are replaced already in the first rendering phase so that the users see the data as soon as possible. If you want to know more details, e.g. what element attributes and bindings are optimized, take a look at the method oneTimeTextBindingAnalyze of TemplateCompiler again in base.js.
As I stated, string concatenation and text escaping cost some CPU cycles. While performance tuning you would like to have a control over it. Let's see how to do it.
In our case we will optimize the rendering process in such way that we will display in the first phase only the name and rest will be displayed in the second phase.
There is a specific binding "flag" on the binding function called "delayable" which controls what phase the binding is taking place. By default all bindings are activated in the first phase which can slow down the initial rendering process.
Setting delayable" property on the binding function we can postpone text concatenation and the binding activation and run it in the second rendering phase. Let's see it in the action.
Binding functions definition
Again our goal is to render only the name in the first phase. So we will need to delay style related bindings:
Then let's use newly defined binding function.
When the template is compiled the renderItem function looks like:
As you could see, string concatenation contains only name (lines 16 ~ 18) and the rest of the binding is activated in the second phase (lines 43 - 45).
I think, WinJS gives us great options how to fine tune the item rendering.