WinJS internals: WinJS.Namespace._lazy
In previous blog post I wrote about WinJS._Signal. Today, it's going to be about another WinJS internal class WinJS.Namespace._lazy.
Problem statement
It's very common for WWA projects to load many Javascript files (I'm worried to write almost all files) in the main application startup page, default.html.
Problem with this approach is that it can negatively hit the initial startup time. Basically, your application will start later. The impact is greatly visible on ARM platforms. All of this is due to the way WinJS classes are defined.
Let's see the example. I created a new blank navigation project in Visual Studio. Then I changed the navigator.js so that we write two ETW StartTM/StopTM events (using msWriteProfilerMark) and we can measure time spent between them:
Let's run the application and measure it.
EventName (Field 3) | Time (s) |
ScriptLoading,Navigator,StartTM | 33.0854791 |
ScriptLoading,Navigator,StoptTM | 33.0862595 |
The time spent is 0.0007s
I use ETW event, recorder by WPRUI and analyzed by WPA. Huh, don’t know what that means? Check the windows performance toolkit for more details and especially this video.
And now let's see what will be the measured time if we only load the script and doesn't execute it.
Let's look at the measure results.
EventName (Field 3) | Time (s) |
ScriptLoading,Navigator-NotExecuted,StartTM | 33.0862669 |
ScriptLoading,Navigator-NotExecuted,StoptTM | 33.0862747 |
The time spent is 0.000007s
The difference is that execuing the script is 100x slower.
Let's go back to the problem
Having all the files loaded in the default.html have the following problems:
- We need to ensure the order is correct
- We hit the performance penalty if the file is loaded, class is defined but not used at all
Let's try to solve this issue:
- We can use a library like RequireJS in order to solve dependecy resolution and script loading - this is just too complex solution for WWA applications
- We can use WinJS.Namespace._lazy which is expose a class on a namespace but doesn't define it
_Lazy approach
The approach is very similar to .NET assembly loader where the assembly is loaded at one but the classes are JITed once they are first time accessed.
So let's rewrite the class into the WinJS.Namespace._lazy style:
Let's measure it:
EventName (Field 3) | Time (s) |
ScriptLoading,Navigator-lazy,StartTM | 16.3186865 |
ScriptLoading,Navigator-lazy,StoptTM | 16.3187682 |
Total time is 0.00008s, so it's 12x slower than not running the definition at all.
Nice, right? But the story doesn't stop here! Lazy construct can help us with solving the ordering the dependencies.
So let's see how it can be solved:
Isn't it great feature? I love it! I must say it's shame WinJS team didn't expose such great and important feature publicly.
Comments
- Anonymous
June 12, 2014
about requirejs: I have set it up in a WWA with 4 lines of code. _lazy is nice though. Do you know if we can use it for WinJS.UI.Pages definitions too?