×
Namespaces

Variants
Actions
(Difference between revisions)

Optimising Nokia Asha Web Apps for speed by eliminating server round trips

From Nokia Developer Wiki
Jump to: navigation, search
hamishwillee (Talk | contribs)
m (Hamishwillee - Remove semicolons that aren't needed)
kiran10182 (Talk | contribs)
m (Kiran10182 - FA templated added)
Line 1: Line 1:
 
[[Category:Series 40 Web Apps]][[Category:Series 40]][[Category:Web]][[Category:Games]][[Category:Code Examples]][[Category:Performance]][[Category:Optimization]]
 
[[Category:Series 40 Web Apps]][[Category:Series 40]][[Category:Web]][[Category:Games]][[Category:Code Examples]][[Category:Performance]][[Category:Optimization]]
 +
{{FeaturedArticle|timestamp=20120930}}
 
{{Abstract|This article explains how to write a highly responsive Series 40 Web App by avoiding server calls after initial load. It uses a Minesweeper clone as example. }}
 
{{Abstract|This article explains how to write a highly responsive Series 40 Web App by avoiding server calls after initial load. It uses a Minesweeper clone as example. }}
  

Revision as of 16:28, 30 September 2012

Featured Article
30 Sep
2012

This article explains how to write a highly responsive Series 40 Web App by avoiding server calls after initial load. It uses a Minesweeper clone as example.

Note.pngNote: This is an entry in the Asha Touch Competition 2012Q3

Article Metadata
Code Example
Source file: Nokia Project
Tested with
Devices(s): Nokia C3-01, Nokia-C2-01
Compatibility
Platform(s): Series 40
Series 40
Device(s): All
Article
Keywords: HTML, JavaScript, CSS, MWL, UX
Created: lorion84 (19 Jul 2012)
Last edited: kiran10182 (30 Sep 2012)

Contents

Introduction

MinesFinder - A game made as WebApp.

If you are writing a Series 40 Web App, you are prepared to cater for the low end of mobile phones. Knowing that the devices which will run your app are very basic should not stop you from trying to deliver a high-end user experience. It is more the other way around, knowing that those phones have limited capabilities should encourage you to use every trick to provide your user with a premium feeling.

There are three main aspects to user experience (UX):

  1. Function - what does the app do, how bug-free is it, etc.
  2. Design - how does the app, and the UI, look
  3. Responsiveness - how does it feel using the app, how fast is it

Of course, these aspects affect each other and you have to trade them off against each other. In this article I concentrate on number 3, the responsiveness. Within this topic, I further concentrate on improving the speed of the application by reducing "browser round-trips".

Browser round-trips have the biggest impact on Series 40 Web App speed. A round-trip takes almost as much time as opening the app. If the user has to wait 2-3 seconds after every single click they won't be very satisfied with the experience. In addition, every round-trip is a possible point of error. If the user has a bad internet connection, a round-trip can break the app.

The code example proves this theory using the example of a Minesweeper clone, MinesFinder. You can find the source in my Nokia Project MinesFinder S40, and an installation file on Nokia Store.

The example allows you to play the game without a single round-trip. You can flag fields, dig for mines, you get a "You Lose" message if you hit a mine and a "You Win" message if you have flagged all mines correctly. In addition there is a counter, showing how many flags you have already planted.

Please note that the Series 40 Web App platform was never intended to be used for highly responsive games. Nevertheless, using a game as example allows me to push the boundaries. The techniques used should be suitable for optimizing most other types of apps.

1. Use MWL where ever you can.

When ever you try to execute any piece of JavaScript, the app will have to make round-trip unless you use methods from Nokia's Mobile Web Library (which can be executed locally). I recommend you keep this documentation close to hand - using mwl.hide("#object") instead of $("#object").hide() makes a huge difference.

This is a pretty basic tip, but mastering the MWL is important for the following tricks as well. Since only MWL gives you the chance to do anything without a round-trip.

Tip.pngTip: You can extract the Mobile Web Library from the installation of the Web Tools. Just search for mwl.js. You can then use the library in other, non Nokia Browser based, projects and increase your familiarity with it.

2. Create everything on startup

Coming from "traditional" web apps, JavaScript is often used to pull in new information when needed (e.g. via an AJAX request). With a Series 40 Web App, every AJAX call and every newly created DOM element will need a server round-trip. So it is often better to load everything that could be needed upfront while the app is starting. Hide it and show it only if needed. For this, you need the command document.write("Some string..."), which is pretty uncommon nowadays.

The following code is used to create 100 DIV-tags which act as counter for the flags.

<script type="text/javascript">
document.write('<div id="counter" class="inline">');
document.write('<div class="inline">10</div>');
for (cc=9; cc>-91; cc--)
{
document.write('<div class="ui-hide">' + cc + '</div>')
}
document.write('</div>');
</script>

Tip.pngTip: Use loops and document.write() to increase the readability of your source code and to reduce the risk of copy/paste/oversight errors.

Tip.pngTip: MWL can only select IDs. Every item which should be accessible needs an ID tag. Add the context to the ID to improve readability: mainpageTab2Button1

Warning.pngWarning: While pre-caching small text elements is no problem, you should be careful with loading images in bigger numbers.

While creating a few hundred almost empty DIVs via document.write() had no influence on the app startup time or the stability, you should always test on-device and have an eye on the restricted resources a Series40 phone offers. Using document.write() is not restricted for the body, you can also use it to create CSS blocks in the header or load script files on start.

3. Use CSS instead of program logic

This point combines the previous 1. and 2. and adds the idea that you move as much logic as possible into CSS which can be checked and manipulated by MWL. Let me explain this further by three examples:

1. Quantity, not Logic

Since the Nokia Browser cannot even execute if () then {} else {} statements without a round-trip, you have to move the logic into the initial loading. In the MinesFinder example, we have two possible actions: digging and flagging. My first idea was that the user has a button to choose whether he wants to dig or to flag. He would then click one game field and the action takes place. This is not possible without a round trip since you would need to check the dig/flag mode.

I moved the logic into the initial loading by not having one dig/flag button and one table with the game fields. Instead the dig/flag button became a toggle for two tabs. Every tab contains a table with the game fields. In addition, every diggable/flaggable field is represented by three different DIVs which are shown according to the game fields state (empty, digged, flagged). For 100 clickable fields I had to create 600 divs.

The following code snippet shows the creation of the table which lets the user dig for mines:

<script type="text/javascript">
for (yy=0; yy<10; yy++)
{
document.write("<tr>");
for (xx=0; xx<10; xx++)
{
if (mf.field[xx][yy] == "X")
{
mwl1 = "mwl.hide('#gamePage'); mwl.show('#loosePage');";
} else {
mwl1 = "mwl.toggleClass('#digDiggedField-" + xx + "-" + yy + "','ui-hide'); mwl.toggleClass('#digEmptyField-" + xx + "-" + yy + "','ui-hide');"
+ "mwl.toggleClass('#flagDiggedField-" + xx + "-" + yy + "','ui-hide'); mwl.toggleClass('#flagEmptyField-" + xx + "-" + yy + "','ui-hide');";
}
 
document.write("<td>");
document.write("<div class='gameField' id='digEmptyField-" + xx + "-" + yy + "' onclick=\"" + mwl1 + "\"></div>");
document.write("<div class='gameField ui-hide' id='digDiggedField-" + xx + "-" + yy + "'>" + mf.field[xx][yy] + "</div>");
document.write("<div class='gameField flaggedField ui-hide' id='digFlaggedField-" + xx + "-" + yy + "'>F</div>");
document.write("</td>");
}
document.write("</tr>");
}
</script>

If the field is flagged or already dug, it gets no onclick event. If the clicked field is a mine, the game shows the #loosePAge. If it is an empty field without a mine, it hides digEmptyField-xx-yy and flagEmptyField-xx-yy and shows digDiggedField-xx-yy and flagDiggedField-xx-yy . It is important to change the state in the dig and the flag tab. Otherwise it would still be possible to flag an already dug field.


2. The Counter

The game shows you how many flags you need to set. At the beginning, the counter shows "10" and whenever you flag a field, it counts down. If you un-flag a field, it goes up. If you plant more than 10 flags, it becomes negative, showing you that some of your flags have to be wrong. The high number of needed DIVs are created in a loop.

<script type="text/javascript">
document.write('<div id="counter" class="inline">');
document.write('<div class="inline">10</div>');
for (cc=9; cc>-91; cc--)
{
document.write('<div class="ui-hide">' + cc + '</div>')
}
document.write('</div>');
</script>

The game fields in the flag view just use a simple MWL command to let the counter work:

onclick = "mwl.setGroupNext('#counter', 'inline', 'ui-hide', 'next');";
onclick = "mwl.setGroupNext('#counter', 'inline', 'ui-hide', 'prev');";

3. Have I won?

The biggest challenge was to check the conditions for victory without doing a round-trip. It is not only necessary that the user flagged all bombs, but they also must not have flagged any bomb-free field. In addition, the "You have won!" page must not only be shown after flagging the last missing mine, it also has to show up after unflagging the last field which has no mine.

To make this possible, I utilized mwl.iterateClass(). A pretty powerful function which increases or decreases a numbered class name until a limit is reached. It then even offers a callback function:

<script type="text/javascript">
for (yy=0; yy<10; yy++)
{
document.write("<tr>");
for (xx=0; xx<10; xx++)
{
[...]
if (mf.field[xx][yy] == "X")
{
mwl2 += "mwl.iterateClass('#gameCounter', 'clearedFieds', 'next', 101, false, 'mwl.hide(\\\'#gamePage\\\'); mwl.show(\\\'#winPage\\\');');";
mwl3 += "mwl.iterateClass('#gameCounter', 'clearedFieds', 'prev', 101, false, '');";
} else {
mwl2 += "mwl.iterateClass('#gameCounter', 'clearedFieds', 'prev', 101, false, '');";
mwl3 += "mwl.iterateClass('#gameCounter', 'clearedFieds', 'next', 101, false, 'mwl.hide(\\\'#gamePage\\\'); mwl.show(\\\'#winPage\\\');');";
}
 
document.write("<td>");
document.write("<div class='gameField' id='flagEmptyField-" + xx + "-" + yy + "' onclick=\"" + mwl1 + mwl2 + "\"></div>");
document.write("<div class='gameField ui-hide' id='flagDiggedField-" + xx + "-" + yy + "'>" + mf.field[xx][yy] + "</div>");
document.write("<div class='gameField flaggedField ui-hide' id='flagFlaggedField-" + xx + "-" + yy + "' onclick=\"" + mwl1 + mwl3 + "\">F</div>");
document.write("</td>");
}
document.write("</tr>");
}
</script>
 
<div id="gameCounter" class="clearedFieds-90">

Whenever a mine is flagged, the clearedFieds-yy will be increased, if the flag is removed, clearedFieds-yy will be decreased. Whenever an empty field is flagged, the clearedFieds-yy will be decreased, if the flag is removed, clearedFieds-yy will be increased.

As soon as clearedFieds-yy reaches 100 (counting for the limit starts at 0), the callback function will show the #winPage.

Warning.pngWarning: If you document.write() an mwl..callback inside an mwl..function inside an onlick-event, the escaping starts to get complicated. There is a useful function in this discussion thread you could use.

Warning.pngWarning: The Nokia Browser cannot work with any class names which are not created upfront. This includes the auto-generated class names from mwl.iterateClass(). If you don't create them, your app will not work on device but in local and cloud preview.

Summary

The Nokia Web Tools, the Mobile Web Library and the Nokia Browser are highly capable tools which enable you to create very responsive apps for a very big audience. But you have to master MWL and you have to think sometimes outside of the box.

Using MWL where ever you can, using JavaScript like a server-side scripting language and moving on-demand logic into CSS and the app start will reduce your server round-trips and increase the responsiveness of your application.

Trade-Offs

Nothing comes without costs. You should keep the following points in mind when you are using the techniques described in this article.

Performance

This application was tested on a C2-01 and a C3-01 and worked fine on both devices. Those devices are not the most powerful Series40 devices, especially compared to what the Asha line has to offer. Nevertheless, using a few hundred DIVs and multiple TABLEs will have at some point an impact on the apps performance. Especially if you
  • use a lot of images or
  • try to animate them.
In this app I used text (F and 0-8) to mark the state of the different game fields and instead of animating the change of views, I just showed and hided them. I haven't tried to use pictures and animations to speed up the development time, but I assume that they could impact performance. In every case, you have to try it on device.


Code Readablilty

If you try to create all content on start by hand, you will run into the problem that your code gets bloated with DIVs and TABLEs. I cannot recommend enough to use document.write("Some string...") and loops to create elements. This way you can also change the code easier later. E.g. changing the size of the field from 10x10 to 10x20 (for full-touch devices) is done by adjusting the loops, not copy/pasting 600 DIVs and changing those IDs.
You can make this even easier if you use pre-defined variables in those loops instead of hard coding them. (Not done in this example.)


Start Up Time

Creating a lot of elements with document.write("Some string...") has the disadvantage that this code has to be run by Nokia's servers when ever the app is started. As more code you run on the servers as longer will the start up take. In theory. In practice, I could not observe any impact on start up time. Executing javascript should be pretty fast compared to accessing foreign origin data and transmitting and scaling images.


Gallery

220 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×