当前位置: 代码迷 >> Web前端 >> 【项目分析】WebService,jQuery,原生对象几种前端加载数据的性能比较(一)
  详细解决方案

【项目分析】WebService,jQuery,原生对象几种前端加载数据的性能比较(一)

热度:675   发布时间:2012-10-20 14:12:47.0
【项目分析】WebService,jQuery,原生对象几种前端加载数据的性能比较(1)

背景

最近的项目遇到了一些性能瓶颈,本篇文章先不谈数据库方面的问题,仅拿前端加载一定量的数据来进行阐述,觉得目前方式比较耗时。前段时间也在做些系统优化,效果并不明显。现在是怀疑出在前端的一些ajax调用以及jQuery本身存在的一些性能问题上;于是,先试着做出些原型,进行各种形式下前端加载数据时的性能对比。

?

详细分析

1. 首先,创建一系列的实体类:

代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->///?<summary>?
///?用户信息?
///?</summary>?
public?class?UserInfo?
{?
????
public?int?UserId?{?get;?set;?}?

????
public?string?UserName?{?get;?set;?}?

????
public?string?Email?{?get;?set;?}?

????
public?Class?Class?{?get;?set;?}?

????
public?List<UserRight>?UserRightList?{?get;?set;?}?
}?

///?<summary>?
///?班级信息?
///?</summary>?
public?class?Class?
{?
????
public?int?ClassId?{?get;?set;?}?

????
public?string?ClassName?{?get;?set;?}?
}?

///?<summary>?
///?用户权限信息?
///?</summary>?
public?class?UserRight?
{?
????
public?int?RightId?{?get;?set;?}?

????
public?string?RightName?{?get;?set;?}?
}

其中包括用户信息类、班级信息类、用户权限类。

?

2. 在Web.config配置一个appsettings节点

<appSettings>
??? <add key="DataCount" value="3000"/>
</appSettings>

表示一次加载的数据量(用户信息数)为3000。

并且将compilation节点的dubug属性设置为false。

?

3. JSON加载数据测试

1)首先先测试 WebService客户端调用并且最后返回JSON加载数据:

代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->function?bindDataWebServiceJson()?{?
????
var?watch?=?new?Stopwatch();?
????watch.start();?

????JsonService.GetUserList(?
????
function(data)?{?

????????
var?builder?=?new?Sys.StringBuilder();?
????????
for?(var?i?=?0,?length?=?data.length;?i?<?length;?i++)?{?
????????????builder.append(String.format(
"<div>UserId:{0},?UserName:{1},?Email:{2}</div>",?data[i].UserId,?data[i].UserName,?data[i].Email));?
????????}?

????????$(
"#msg2").html(builder.toString());?
????????watch.stop();?
????????$(
"#time2").html("用时:"?+?watch.ms?+?"毫秒.");?

????});?
}

(注:这里引入了一个Stopwatch计时器,很简单,具体可以参考:http://www.cnblogs.com/liping13599168/archive/2009/08/15/1546673.html)

通过代码,我们可以看到它调用了JsonService.asmx中Web服务的GetUserList方法:

代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->[WebMethod]?
public?List<UserInfo>?GetUserList()?
{?
????
int?count?=?Convert.ToInt32(ConfigurationManager.AppSettings["DataCount"]);?
????List
<UserInfo>?list?=?new?List<UserInfo>();?
????
for?(int?i?=?0;?i?<?count;?i++)?
????{?
????????list.Add(
new?UserInfo?{?UserId?=?i,?UserName?=?"leepy"?+?i,?Email?=?"sunleepy"?+?i?+?"@gmail.com"?});?
????}?
????
return?list;?
}

返回了一个3000条记录的UserInfo实体列表,而前端页面通过对列表返回客户端时的Json对象,进行Html字符串拼接,最后通过jQuery的Dom元素html(‘…’)方法赋值。运行加载结果为:

?

目前我的项目大多数就是采用这样的模式。

2)接着,如果使用jQuery的$.ajax调用并且最后JSON加载数据:

代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->function?bindDatajQueryAjaxJson()?{?
????
var?watch?=?new?Stopwatch();?
????watch.start();?
????$.ajax({?
????????url:?
"JsonHandler.ashx",?
????????dataType:?
'json',?
????????cache:?
false,?
????????success:?
function(data)?{?
????????????
var?builder?=?new?Sys.StringBuilder();?
????????????
for?(var?i?=?0,?length?=?data.length;?i?<?length;?i++)?{?
????????????????builder.append(String.format(
"<div>UserId:{0},?UserName:{1},?Email:{2}</div>",?data[i].UserId,?data[i].UserName,?data[i].Email));?
????????????}?
????????????$(
"#msg4").html(builder.toString());?

????????????watch.stop();?
????????????$(
"#time4").html("用时:"?+?watch.ms?+?"毫秒.");?
????????}?
????});?
}

通过JsonHandler.ashx的页面处理程序执行返回数据:

代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->public?void?ProcessRequest?(HttpContext?context)?{?
????context.Response.ContentType?
=?"application/x-javascript";?
????
int?count?=?Convert.ToInt32(ConfigurationManager.AppSettings["DataCount"]);?

????List
<UserInfo>?list?=?new?List<UserInfo>();?
????
for?(int?i?=?0;?i?<?count;?i++)?
????{?
????????list.Add(
new?UserInfo?{?UserId?=?i,?UserName?=?"leepy"?+?i,?Email?=?"sunleepy"?+?i?+?"@gmail.com"?});?
????}?
????StringBuilder?builder?
=?new?StringBuilder();?
????
string?data?=?"[";?
????
for?(int?i?=?0,?length?=?list.Count;?i?<?length;?i++)?
????{?
????????data?
+=?"{"?+?string.Format("'UserId':'{0}','UserName':'{1}',?'Email':'{2}'",?list[i].UserId,?list[i].UserName,?list[i].Email)?+?"},";?
????}?
????data?
=?data.TrimEnd(',')?+?"]";?
????context.Response.Write(data);?
}

也是3000条用户数据,运行加载结果为:

比WebService快了一些。

3)接着,使用$.getJSON来调用并且JSON加载数据:

代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->function?bindDatajQueryGetJson()?{?
????
var?watch?=?new?Stopwatch();?
????watch.start();?
????$.getJSON(
"JsonHandler.ashx",?function(data)?{?
????????
var?builder?=?new?Sys.StringBuilder();?
????????
for?(var?i?=?0,?length?=?data.length;?i?<?length;?i++)?{?
????????????builder.append(String.format(
"<div>UserId:{0},?UserName:{1},?Email:{2}</div>",?data[i].UserId,?data[i].UserName,?data[i].Email));?
????????}?
????????$(
"#msg5").html(builder.toString());?

????????watch.stop();?
????????$(
"#time5").html("用时:"?+?watch.ms?+?"毫秒.");?
????});?
}

同样通过JsonHandler.ashx的页面处理程序执行返回数据,运行加载结果为:

和$.ajax相差无几,实际从jQuery代码中可以看出实际上$.getJSON调用的就是$.ajax函数:

代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->get:?function(url,?data,?callback,?type)?
{?
????
//?shift?arguments?if?data?argument?was?ommited?
????if?(jQuery.isFunction(data))?
????{?
????????callback?
=?data;?
????????data?
=?null;?
????}?

????
return?jQuery.ajax({?
????????type:?
"GET",?
????????url:?url,?
????????data:?data,?
????????success:?callback,?
????????dataType:?type?
????});?
},

getJSON:?
function(url,?data,?callback)?
{?
????
return?jQuery.get(url,?data,?callback,?"json");?
},

4)接着,使用xmlHttp.js的原生对象调用并且JSON加载数据:

代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->function?bindDataPrototypeAjaxJson()?{?
????
var?watch?=?new?Stopwatch();?
????watch.start();?
????Request.sendGET(
"JsonHandler.ashx",?false,?function(data)?{?

????????
var?jsonData?=?JSON.parse(data,?null);?
????????
var?builder?=?new?Sys.StringBuilder();?
????????
for?(var?i?=?0,?length?=?jsonData.length;?i?<?length;?i++)?{?
????????????builder.append(String.format(
"<div>UserId:{0},?UserName:{1},?Email:{2}</div>",?jsonData[i].UserId,?jsonData[i].UserName,?jsonData[i].Email));?
????????}?
?????????$(
"#msg11").html(builder.toString());?
????????watch.stop();?
????????$(
"#time11").html("用时:"?+?watch.ms?+?"毫秒.");??
????});?
}

其中var jsonData = JSON.parse(data, null); 用到了一个json2.js 的开源JSON解析组件,将data的字符串转换为一个JSON对象。运行结果为:

和jQuery的$.ajax函数也是基本相差无几。

测试说明:$.ajax,$.getJSON,原生对象返回JSON加载数据的效率基本一样,比WebService的效率好些。

?

4. Html字符串加载数据测试

1)WebService客户端调用返回Html字符串加载数据:

代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->function?bindDataWebServiceHtml()?{?
????
var?watch?=?new?Stopwatch();?
????watch.start();?

????HtmlService.GetUserListHtml(?
????
function(data)?{??
????????????$(
"#msg1").html(data);?
????????watch.stop();?
????????$(
"#time1").html("用时:"?+?watch.ms?+?"毫秒.");?
????});?
}

通过代码,我们可以看到它调用了HtmlService.asmx中Web服务的GetUserListHtml方法:

代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->[WebMethod]?
public?string?GetUserListHtml()?{?
????List
<UserInfo>?list?=?GetUsers();?

????StringBuilder?builder?
=?new?StringBuilder();?
????
for?(int?i?=?0,?length?=?list.Count;?i?<?length;?i++)?
????{?
????????builder.AppendFormat(
"<div>UserId:{0},?UserName:{1},?Email:{2}</div>",?list[i].UserId,?list[i].UserName,?list[i].Email);?
????}?
????
return?builder.ToString();?
}

将前端页面对于Html字符串拼接的工作放在WebService中(或者相关后台代码)中去执行,最后通过jQuery的Dom元素html(‘…’)方法赋值。运行加载结果为:

2)jQuery的$.ajax调用返回Html字符串加载数据:

代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->function?bindDatajQueryAjaxHtml()?{?
????
var?watch?=?new?Stopwatch();?
????watch.start();?
????$.ajax({?
????????type:?
"get",?
????????url:?
"HtmlHandler.ashx",?
????????cache?:?
false,?
????????success:?
function(data)?{?
????????????$(
"#msg3").html(data);?
????????????watch.stop();?
????????????$(
"#time3").html("用时:"?+?watch.ms?+?"毫秒.");?
????????}?
????});?
}

通过HtmlHandler.ashx的页面处理程序执行返回数据:

代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->public?void?ProcessRequest?(HttpContext?context)?{?
????????
int?count?=?Convert.ToInt32(ConfigurationManager.AppSettings["DataCount"]);?
????????List
<UserInfo>?list?=?new?List<UserInfo>();?
????????
for?(int?i?=?0;?i?<?count;?i++)?
????????{?
????????????list.Add(
new?UserInfo?{?UserId?=?i,?UserName?=?"leepy"?+?i,?Email?=?"sunleepy"?+?i?+?"@gmail.com"?});?
????????}?
????????StringBuilder?builder?
=?new?StringBuilder();?
????????
for?(int?i?=?0,?length?=?list.Count;?i?<?length;?i++)?
????????{?
????????????builder.AppendFormat(
"<div>UserId:{0},?UserName:{1},?Email:{2}</div>",?list[i].UserId,?list[i].UserName,?list[i].Email);?
????????}?
????????context.Response.Write(builder.ToString());?
}

运行加载结果为:

?

比WebService也快了一些。

3)原生Ajax调用返回Html字符串加载数据:

代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->function?bindDataPrototypeAjaxHtml()?{?
????
var?watch?=?new?Stopwatch();?
????watch.start();?
????Request.sendGET(
"HtmlHandler.ashx",?false,?function(data)?{?
????????$(
"#msg6").html(data);?
????????watch.stop();?
????????$(
"#time6").html("用时:"?+?watch.ms?+?"毫秒.");?
????});?
}

运行载结果为:

和jQuery的$.ajax函数也是基本相差无几。

?

测试说明:$.ajax,$.getJSON,原生对象返回返回Html字符串加载数据的效率基本一样,比WebService的效率好些;并且通过3和4的比较,说明通过在后台拼接Html字符串,比在前台来拼接的过程来得更高效。

?

5. 在我的实例中,大家也许注意到了有“原生Html赋值”和“jQuery Dom赋值”的单选按钮,这是什么呢?很简单,前者就是形如document.getElementById(‘…’),后者就是我们项目中使用的$('#…’).html(‘…’)这样的形式。这两种创建DOM元素上有什么差别吗?用测试说话。

我任意挑选几张对比截图:

? ??

??

?

测试说明:使用原生对象Html赋值比jQuery的Html赋值性能上提升了许多;换句话,就是尽量多使用document.getElementById(‘…’)这样来赋值。

?

6. 最后我们通过cs代码隐藏文件加载数据:

代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->protected?void?Page_Load(object?sender,?EventArgs?e)?
{?
????Stopwatch?watch?
=?new?Stopwatch();?
????watch.Start();?
????
int?count?=?Convert.ToInt32(ConfigurationManager.AppSettings["DataCount"]);?

????List
<UserInfo>?list?=?new?List<UserInfo>();?
????
for?(int?i?=?0;?i?<?count;?i++)?
????{?
????????list.Add(
new?UserInfo?{?UserId?=?i,?UserName?=?"leepy"?+?i,?Email?=?"sunleepy"?+?i?+?"@gmail.com"?});?
????}?
????StringBuilder?builder?
=?new?StringBuilder();?
????
for?(int?i?=?0,?length?=?list.Count;?i?<?length;?i++)?
????{?
????????builder.AppendFormat(
"<div>UserId:{0},?UserName:{1},?Email:{2}</div>",?list[i].UserId,?list[i].UserName,?list[i].Email);?
????}?
????msg7.InnerHtml?
=?builder.ToString();?
????time7.Text?
=?"用时:"?+?watch.ElapsedMilliseconds?+?"毫秒.";?
}?

public?int?GetDataCount()?
{?
????
return?Convert.ToInt32(ConfigurationManager.AppSettings["DataCount"]);?
}

运行结果为:

使用后台代码进行页面上的业务逻辑实现是相当高效的。

测试说明:在页面第一次加载的时候,尽量能够在服务端后台代码对服务器控件进行数据绑定,也就是说多使用runat=”server”这样的服务端控件,特别可以充分使用repeater控件的优势来进行数据绑定。

?

总结

再把前面的测试结果列举一下:

1. .ajax,$.getJSON,原生对象返回JSON加载数据的效率基本一样,比WebService的效率好些。

2. $.ajax,$.getJSON,原生对象返回返回Html字符串加载数据的效率基本一样,比WebService的效率好些;

3. 通过测试3和测试4的比较,说明通过在后台拼接Html字符串,比在前台来拼接的过程来得更高效。

4. 使用原生对象Html赋值比jQuery的Html赋值性能上提升了许多;换句话,就是尽量多使用document.getElementById(‘…’)这样来赋值。

5. 在页面第一次加载的时候,尽量能够在服务端后台代码对服务器控件进行数据绑定,也就是说多使用runat=”server”这样的服务端控件,特别可以充分使用repeater控件的优势来进行数据绑定。

?

????? 这是我对于前端页面加载数据时,通过几种方式测试得出来的结果以及结论,如果不妥的地方,希望大家能够提出,欢迎交流,谢谢指教:)?

????? 下一篇,我会介绍下,在当前项目下,如何能够快速优化当前的系统,比如我现在是使用WebService,如何在不改变前端JS代码的情况下,切换到$.ajax或者原生对象中去,有点像“适配器”的概念吧。

  相关解决方案