×
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 - Bot update - Add ArticleMetaData)
lorion84 (Talk | contribs)
(Lorion84 -)
Line 28: Line 28:
  
 
== Introduction ==
 
== Introduction ==
 
+
[[File:Minesfinder-1.png|thumb|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.
 
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.
  
Line 71: Line 71:
 
{{Warning|While pre-caching small text elements is no problem, you should be careful with loading images in bigger numbers.}}
 
{{Warning|While pre-caching small text elements is no problem, you should be careful with loading images in bigger numbers.}}
  
Using {{Icode|document.write();}} is not restricted for the  {{Icode|body}}, you can also use it to create CSS blocks in the header or load script files on start,
+
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 {{Icode|document.write();}} is not restricted for the  {{Icode|body}}, you can also use it to create CSS blocks in the header or load script files on start.
  
  

Revision as of 20:05, 25 July 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
Installation file: http://eve-c.org/minesfinder
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: lorion84 (25 Jul 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 greatest impact on Series 40 Web App speak. 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. I am attempting to get it into the Nokia Store - until then you can visit http://eve-c.org/minesfinder with your Nokia Browser to play it.

The example allows you to play the game without a single round-trip. You can flag fields, dig for mines, you get a "You Loose" 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.


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 Template: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.

Gallery

153 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.

×