2013年8月14日星期三

How jQuery Mobile Eats PhoneGap Performance, See Experiment


As we know, jQuery Mobile renders a lot of HTML for a simple element/widget. For example, the below picture(from jQM demos) shows the HTML source code (right) of a simple list item(left).
However, to make such a list item, the html can be as simple as just: <li>Acura</li>(don’t know how? Leave a comment.)
But how will HTML elements affect the performance? Let’s take an experiment to see.
I wrote a simple page to test it. Open live demo for web browser(PC & Phone)
 <!DOCTYPE html>  
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1, width=device-width" />
<title></title>
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.min.js"></script>
</head>
<body>
<p>
<input type="button" value="Render jQM" id="btnRenderjQM"/>
<input type="button" value="Render Custom" id="btnRenderCustom"/>
</p>
<p><b>Time: </b><span id="time">0</span></p>
<ul id="result" style="height: 200px; overflow: auto;"></ul>
<script language="javascript" type="text/javascript">
var time = null;
$(document).ready(function() {
var li1 = '<li data-corners="false" data-shadow="false" data-iconshadow="true" data-wrapperels="div" data-icon="arrow-r" data-iconpos="right" data-theme="c" class="ui-btn ui-btn-icon-right ui-li-has-arrow ui-li ui-first-child ui-btn-up-c">\
<div class="ui-btn-inner ui-li">\
<div class="ui-btn-text"><a href="#" class="ui-link-inherit">Acura</a></div>\
<span class="ui-icon ui-icon-arrow-r ui-icon-shadow">&nbsp;</span></div>\
</li>';
var li2 = '<li>Acura</li>';
$("#btnRenderjQM").click(function() {
var $ul = $("#result");
$ul.empty();
var html = '';
for (var i = 0; i < 1000; i++) {
html += li1;
}
time = new Date();
$ul.html(html);
$("#time").html(new Date() - time);
});
$("#btnRenderCustom").click(function() {
var $ul = $("#result");
$ul.empty();
var html = '';
for (var i = 0; i < 1000; i++) {
html += li2;
}
time = new Date();
$ul.html(html);
$("#time").html(new Date() - time);
});
});
</script>
</body>
</html>
There are two buttons on the test page, one appends 1000 jQueryMobile list items to the list, while the other appends 1000 simple list items.
Let’s see some charts.
Test in firefox:

Test in google chome:

Test on Android Phone:
The charts mean: HTML elements eat performance. If we use simple HTML elements to render a page, it will save about 80% performance than using jQM. If it’s a small page, that would be OK using jQM, if it’s a complex page, I recommend you write the HTML elements by yourself.
The above test page can be viewed online here: live demo for web browser(PC &Phone).
Feel free to make comments or ask questions.

2013年8月12日星期一

My PhoneGap With jQuery Mobile Development Experience

Recently my PhoneGap team has been working with jQuery Mobile for a few clients. The overall development experience is really bad.

Project 1: tablet

The first APP I want to say is for tablet. Our team joined the development when the APP was about 90% done. That APP used jQuery Mobile and also backbone.
When we joined the development, the code looked not very professional. There are mainly two files for the project, two very big ones. One is the index.html that had over 2000 lines, and the other is index.js that has over 5000 lines of code.
Our first tasks are very small and were done quickly, but we still suffered from the too large code. So we advised the client refactor, and the client accepted. We then re-designed the code architecture and separated the big index.js into many small ones based on functions. The JS code became much clear, but the index.html is still very large(no change).
Later the client said the whole APP performance was not good, then we tried many methods but finally we have to remove usage of jQuery Mobile. It is because jQuery Mobile generates too many html elements for a simple element, such as a button. When the data become a little large, it costs a lot of time rendering so many html element. And the html elements each performance during the whole lifetime of the page.
Another example:
For the above item template, we can change it to:
<li>Acura<span></span></li> , even the <span> is not necessary.
For some pages with big data, we refactored the html to use as few html as possible. And the performance become much better.

Project 2: iPhone

We joined the project also from half way. One of our tasks is to list all contacts and search and choose. Normally, a phone has more than 200 contacts. At the beginning, we used jQuery Mobile listview because the project was already using jQuery Mobile. The list item template is not complex, but the performance was very bad. It cost about 3 seconds to render 300 contacts.
Then we tried removing using listview, instead, we wrote a very simple UL, and the performance become much better. We also spent much time on the listview item template, since it doesn’t work well and not easy to use.
For this project, there are also mainly two big files: index.js and index.html. The code is hard to read or maintain. We need to press CTRL+F to navigate to the right page all the time. It’s really a nightmare.

In conclusion

The two projects originally used a lot of jQuery Mobile features, but finally many of them are removed due to performance issues. I think jQuery Mobile is only suitable for web applications, not for PhoneGap, since performance is really a big concern in PhoneGap.
Till this moment, I haven’t seen any good jQuery Mobile project architecture. A good code architecture should keep the code easy to read, easy to maintain, and any developer knows where to put the code. Generally, each file should have less than 300 lines of code, each method should have less than 30 lines of code.

2013年7月31日星期三

PhoneGap Development Best Practice(1) - Using Mock


Here I'd like to share with you a phonegap development practice from our phonegap team -- using mock. Then you don't have to test phonegap API related functions on your mobile devices, instead you can test the functions in web browser. You will find it saving you a lot of time.
It's so easy to use
We name the mock file as cordova.mock.js. You can switch beween mock and real cordova by adding/deleting the ".mock" to/from the script reference line.
Using mock:
<script src="cordova.mock.js" type="text/javascript"></script>
Using real:
<script src="cordova.js" type="text/javascript"></script>
Write the rest of code just like you are using the real cordova.js, becasue the two files works the same.
How to make the cordova.mock.js?
We have created a github repository for cordova.mock.js. It's now not 100% complete, but we'll continue to mock more phonegap API to it. We also welcome you to contribute to this repo.
Part of sample code.
if(window.navigator == undefined) {
window.navigator = { };
}
navigator.contacts = {
find: function(contactFields, contactSuccess, contactError, contactFindOptions) {
var contacts = [
{
displayName: "Mike",
name: {
familyName: 'R',
formatted:'Mike R'
},
phoneNumbers: [
{
type: "string",
value: "0722829323123",
pref: false
}
]
},
{
displayName: "Leo",
phoneNumbers: [
{
type: "string",
value: "03837234343",
pref: false
},
{
type: "string",
value: "005543834",
pref: true
}
]
}
];
contactSuccess(contacts);
}
};

var ContactFindOptions = function() {
this.filter = "";
this.multiple = false;
};
You can also make it by your self according to your project requirements. It's really easy.
How do you like this idea? Please feel free to make any comment.

2013年6月13日星期四

New demo added to nova phonegap framework

We have made a new demo to our phonegap framework. It is used to manage your anual targets. I have been using it for months and find it quite useful.

There is currently no published android or iOS version, only source code available.

Checkout the below path:



2013年3月21日星期四

A PhoneGap + jQuery Mobile App

We have made a phonegap app. We used jquery mobile to build the UI, which saves us much time during the development.

The app is now running on iOS, android, windown phone.

The client is desirous to make the application work in different platforms, such as Android, iOS , WindowsPhone. This cross-platform application should include the functions such as a native-like UI, manipulating remote data, taking picture from both camera and photo library, saving configuration locally, uploading files and so on.

To see more details and screenshots: http://www.novasoftware.com/Case_Studies/Cases/PhoneGap_Plan_Management.aspx

If you need to outsource your phonegap development, please learn more about our phonegap development service

2013年3月5日星期二

Three Most Important Skills For PhoneGap Developers

I have been developing PhoneGap apps for some time. A few days ago, a new member of our PhoneGap team asked me a question: what are the most important skills for a PhoneGap developer?
This blog shows my personal ideas on the above question. I'm open to see your opinions.

First, good understanding of Javascript OOP

The most important skills of a PhoneGap developer should be the javascript skills. And a javascript expert must know javascript OOP(object-oriented-programming) well.
There will be many javascripts in your PhoneGap apps. You will need to consider how to organize the javascripts, which will be quite different from common web applications. For common web apps, you probably use no javascript in OOP way. You probably write code like below:

$(document).ready(function(){
$("#btnSave").click(function(){
//todo: save the form
})
});
But for PhoneGap apps, too much code like above will make your app hard to maintain. Here, I recommend you write your PhoneGap app in single-page-application, since it behaves more like native apps, instead of web apps, and it will be quite easy to navigate through pages.
In my PhoneGap experience, I found the below javascript OOP skills very important:
  1. Class. Normally I use the below code to define a class.

    var ProductEditor = function(productId) {
    this.productId = productId;
    };

    ProductEditor.prototype.save = function(callback) {
    //todo: save the form
    };
  2. Namespace. For example:

    if(window.demo == undefined) {
    demo = { };
    }
    if(demo.services == undefined) {
    demo.services = { };
    }

    //define a class under the namespace
    demo.services.ProductService = function () {

    };

    demo.services.ProductService.prototype.getProductById = function(id) {
    //todo: return product
    };

    //to use the service
    var service = new demo.services.ProductService();
    var product = service.getProductById(1);
  3. Class inheritance.

    demo.services.EmailServiceProvider = function() {
    this.host = "smtp.gmail.com";
    this.port = 587;
    };

    demo.services.EmailServiceProvider.prototype.sendEmail = function(subject, body, to, cc) {

    };

    //define another that inherits the above provider
    demo.services.ContactUsEmailServiceProvider = function() {
    demo.services.EmailServiceProvider.call(this);
    };

    demo.services.ContactUsEmailServiceProvider.prototype = new demo.services.EmailServiceProvider();
    demo.services.ContactUsEmailServiceProvider.constructor = demo.services.ContactUsEmailServiceProvider;

    //override the parent method
    demo.services.ContactUsEmailServiceProvider.prototype.sendEmail = function(body) {
    demo.services.EmailServiceProvider.prototype.sendEmail.call(this, "contact us", body, "cail@shinetechchina.com");
    };

    //define new method
    demo.services.ContactUsEmailServiceProvider.prototype.saveToDB = function(body) {

    };
  4. For other javascript OOP skills, you can google them.

Second, have the ability to handle touch events

Though in most cases, we don't need to handle touch events by ourselves, as the third-party libs ( jquery mobile, Nova PhoneGap framework, Sencha Touch, KendoUI, etc ) do it for us, we still need to know there are 3 very important touch events: touchstart, touchmove, touchend.
If you want to do custom scroll/click/drag/double click/long press/..., or any other amazing effects, you will need to work with the 3 events. If you want to learn more, Nova PhoneGap framework should be a good resource, as it handles the touchs in a simple way, and easy to read easy to learn.

Third, know well of PhoneGap API

  • What features are supported by PhoneGap? What features are not?
  • What are the free plugins?
  • What kinds of projects are not suitable for to be developed in PhoneGap?
A PhoneGap developer should know the answers to the above questions well, and keep an eye on the API upodates because the PhoneGap team work productively.

References in this post

2013年1月16日星期三

Entity Framework For Html5 SQLite, PhoneGap Data Access Framework

Notice: The HTML5 SQLite library has been picked out from Nova PhoneGap Framework, so it is a standalone library now. The latest source code and documentation have been moved to github https://github.com/leotsai/html5sqlite
Nova PhoneGap Framework has developed a framework for data access in html5 SQLite. It works in a similar way with the C# EntityFramework (EF). See documentation
Take a look at the below code then you will know it's so easy to define your database and entities, and query, add, update, delete entities from the db.

// define dbContext & entities------------------------------------
var DemoDataContext = function () {
nova.data.DbContext.call(this, "Demo", style="color: #a31515">"1.0", "Demo DB", 1000000);

this.users = new nova.data.Repository( style="color: blue">this, User, "users");
this.roles = new nova.data.Repository( style="color: blue">this, Role, "roles");
};

DemoDataContext.prototype = new nova.data.DbContext();
DemoDataContext.constructor = DemoDataContext;

var User = function () {
nova.data.Entity.call( style="color: blue">this);
this.name = "";
this.password = "";
this.birthYear = 1980;
this.createdDate = new Date();
this.deleted = false;
};
User.prototype = new nova.data.Entity();
User.constructor = User;

var Role = function () {
nova.data.Entity.call( style="color: blue">this);
this.name = "";
this.createdDate = new Date();

};
Role.prototype = new nova.data.Entity();
Role.constructor = Role;
// end define dbContext & entities------------------------------------

// service methods----------------------------------------------------
function getAllUsers(callback) {
new DemoDataContext().users.toArray(function (users) {
alert(users.length);
callback(users);
});
}

function getUserByName(name, callback) {
new DemoDataContext().users.where("name='" + name + "'").toArray( style="color: blue">function (users) {
callback(users.firstOrDefault());
});
}

function addRole(roleName, callback) {
var role = new Role();
role.name = roleName;
var db = new DemoDataContext();
db.roles.add(role);
db.saveChanges(callback);
}

function updateUserPassword(username, password, callback) {
getUserByName(username, function (user) {
if (user == null) {
throw "no user found.";
}
user.password = password;
var db = new DemoDataContext();
db.users.update(user);
db.saveChanges(callback);
});
}

function deleteUserByName(name, callback) {
getUserByName(name, style="color: blue">function (user) {
if (user == null) {
throw "no user found.";
}
var db = new DemoDataContext();
db.users.remove(user);
db.saveChanges(callback);
});
}

// end service methods----------------------------------------------------