Optimising Nokia Asha Web Apps for speed by eliminating server round trips
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.
Article Metadata
Code Example
Tested with
Compatibility
Article
Contents |
Introduction
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):
- Function - what does the app do, how bug-free is it, etc.
- Design - how does the app, and the UI, look
- 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.
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>
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.
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.


Contents
Hamishwillee - Great job - subedit and a few suggestions
Hi
I have given this a basic subedit - improving the English where needed, tidying up the wiki formatting, fixing a few odd looking links. I also added performance/optimisation categories. The most significant change I made was to change the heading to "Create everything on startup" - this is more clear as an instructional heading. Hope you are OK with this - check the revision history for more information.
In terms of further improvements, the "big picture" fix that needs to be made is the title. "MinesFinder" is a description of the app not the article. The title should help the person decide if they want to read the article - something like "Optimising Nokia Asha Web Apps for speed and responsiveness", or "Optimising Nokia Asha Web Apps for speed by using locally executed JavaScript" - I'm sure you might be able to find something better.
The other change I might make is to have one of your gallery images up near the top - perhaps left-floated. An image "tells a thousand words".
In my opinion, it would be great if you could add a few more words about the trade offs you made. For example, you've created 600 divs for your map in order to avoid the round trip. What are the costs of this? Obviously this will consume more memory - is this likely to crash the device? Will it significantly affect the initial creation time of the app? If you needed to modify the app - for example say you decided to make this slightly smaller or bigger would the way this has been done make changing the app much harder or easier?
The only "problem" I have with this article is that Nokia Asha Web Apps aren't really intended for writing this sort of app - you'd normally use Java for this sort of thing. Series 40 web apps are primarily intended for mobilising existing web based content - where you're going to need a round trip for the very nature of the app.
That said, I think its both interesting and useful, and there will be people who would rather develop in this way than using Java. You've enabled them - so thanks for this very useful and generally well written article.
Regards
Hamishhamishwillee 10:24, 24 July 2012 (EEST)
Hamishwillee - Make your profile public?
PS It would also be really nice if you could make your profile public so your "fans" can find out a bit more about you - http://www.developer.nokia.com/Profile/?u=lorion84 - at the moment its empty except for the dynamic content.
Regards
Hamishhamishwillee 10:26, 24 July 2012 (EEST)
Lorion84 - Thank you for your feedback.
You are right, the title is not very well chosen. I have to change it.
About the trade-offs, I tried to cover your points in the "Tips" and "Warning". Problem here is, I can only guess. The performance does not seem to be affected. I used a C3-01 for testing, which is not the most powerful device, and had 0 problems with those ~800 DIVs. As long as they are empty and most of the time hidden, they should not make any problems. The initial creation also never suffered. Transferring an image has a much higher impact. Readability is a problem, that's why I recommend using document.write, this way it should improve readablilty AND maintainability.
Yes, I know, WebApps are not the preferred way for creating games. But if the UX good, why not? I love to try to push the boundaries.
Will update my profile.lorion84 19:53, 25 July 2012 (EEST)
Hamishwillee - Thanks
Hi Lorion
I think it may be worth making those comments above in a separate section "Trade offs" in the document - it is all useful information for people to understand that you've not run into any problems but that it is possible you might, that this has no real impact on initial creation - especially when compared to image transfer, and why you use document.write(). However it is completely your call - you've clearly thought about this and I see your reasoning
From a competition perspective, none at all. Indeed the concepts will certainly be useful for developers who are creating connected apps.
My comment is purely because I'm aware that this is not the best framework for creating non-connected games and I'd be careful in my own articles to make that clear for other readers who might not be as educated on the framework. However this is a great example for making your points. Feel free to ignore.
Regards
Hamishhamishwillee 08:53, 26 July 2012 (EEST)
Lorion84 - okay
Is it even possible to change the name of the article? Or do I have to create a new one and copy the content?
I'll add a tradeoff segment in the summary.
Hamishwillee - Yes you can move this
There is a little eye icon up the top of the page - the drop down gives you the "move" option.
Or I can move it if you provide the new name you would be happy with.hamishwillee 09:03, 27 July 2012 (EEST)
Lorion84 - Yes, please move the page
The new title should be "Optimising Nokia Asha Web Apps for Speed by Eliminating Server Round Trips"
Thank you. Can't wait for the competition to end.lorion84 11:48, 28 July 2012 (EEST)
Hamishwillee - Done!
Hi Lorion
Fixed.
I can. I really enjoy seeing what you guys can come up with. Only a couple of days until first round ends now though!
Regards
Hhamishwillee 08:06, 30 July 2012 (EEST)