zoukankan      html  css  js  c++  java
  • 【项目分析】WebService,jQuery,原生对象几种前端加载数据的性能比较(1)

    背景

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

    详细分析

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

    代码
    /// <summary> 
    /// 用户信息 
    /// </summary> 
    public class UserInfo 

        
    public int UserId { getset; } 

        
    public string UserName { getset; } 

        
    public string Email { getset; } 

        
    public Class Class { getset; } 

        
    public List<UserRight> UserRightList { getset; } 


    /// <summary> 
    /// 班级信息 
    /// </summary> 
    public class Class 

        
    public int ClassId { getset; } 

        
    public string ClassName { getset; } 


    /// <summary> 
    /// 用户权限信息 
    /// </summary> 
    public class UserRight 

        
    public int RightId { getset; } 

        
    public string RightName { getset; } 
    }

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

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

     

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

    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快了一些。

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

    和$.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"falsefunction(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字符串加载数据:

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

    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也快了一些。

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

    代码
    function bindDataPrototypeAjaxHtml() { 
        
    var watch = new Stopwatch(); 
        watch.start(); 
        Request.sendGET(
    "HtmlHandler.ashx"falsefunction(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或者原生对象中去,有点像“适配器”的概念吧。

    源代码下载

  • 相关阅读:
    css3 flex 布局
    用CSS3 & jQuery创建apple TV海报视差效果
    JavaScript知识点的总结
    javascript 常用DOM操作整理
    html打造动画【系列4】哆啦A梦
    如何掌握jQuery插件开发(高能)
    前端基础进阶(一):内存空间详细图解
    JavaScript中数组对象详解
    [zhuan]JNIEnv解析
    在 C Level 用 dlopen 使用 第三方的 Shared Library (.so)
  • 原文地址:https://www.cnblogs.com/liping13599168/p/1731168.html
Copyright © 2011-2022 走看看