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

背景

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

 

详细分析

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

代码
///   <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加载数据:

代码
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方法:

代码
[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(‘…’)方法赋值。运行加载结果为:

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

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

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

代码
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的页面处理程序执行返回数据:

代码
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,jQuery,原生对象几种前端加载数据的性能比较(1)

比WebService快了一些。

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

代码
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的页面处理程序执行返回数据,运行加载结果为:

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

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

代码
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加载数据:

代码
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对象。运行结果为:

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

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

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

 

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

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

代码
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方法:

代码
[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(‘…’)方法赋值。运行加载结果为:

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

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

代码
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的页面处理程序执行返回数据:

代码
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,jQuery,原生对象几种前端加载数据的性能比较(1) 

比WebService也快了一些。

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

代码
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代码隐藏文件加载数据:

代码
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或者原生对象中去,有点像“适配器”的概念吧。

 

源代码下载

你可能感兴趣的:(webservice)