W者从事AJAX 斚w的研发多q_参与开发了目前国内较ؓ成熟的AJAXq_ -dorado 。根据笔者的l验Q导致这U结果的Ҏ(gu)原因q不在AJAX 。很多时候系l响应速度的降低都是由不够合理的界面设计和不够高效的编E习惯造成的。下面我们就来分析几?AJAX 开发过E中需要时L意的环节?/p>
<!-- [if !supportLists]-->n <!-- [endif]-->合理的用AJAX客户端编E和q程q程调用?/p>
AJAX客户端的~程主要都是Z JavaScript 的。?JavaScript 是一U解释型的编E语aQ它的运行效率相对于 Java {都要稍逊一{V同?JavaScript 又是q行在浏览器q样一个严格受限的环境当中。因此开发h员对于哪些逻辑可以在客L执行应该有一个清醒的认识?/p>
在实际的应用中究竟应该怎样使用 客户端编E,q依赖于开发h员的l验判断。这里很多问题是只可意会的。由于篇q有限,在这里我们大致归U_下面q几个注意事:
<!-- [if !supportLists]-->u <!-- [endif]-->可能避免频J的使用q程q程调用Q例如避免在循环体中使用q程q程调用?/p>
<!-- [if !supportLists]-->u <!-- [endif]-->如果可能的话可能?AJAX 方式的远E过E调用(异步方式的远E过E调用)?/p>
<!-- [if !supportLists]-->u <!-- [endif]-->避免重量的数据操作放|在 客户端。例如:大批量的数据复制操作、需要通过大量的数据遍历完成的计算{?/p>
<!-- [if !supportLists]-->n <!-- [endif]-->改进?DOM 对象的操作方式?/p>
客户端的~程中,?DOM 对象的操作往往是最Ҏ(gu)占用 CPU 旉的。而对?DOM 对象的操作,不同的编E方法之间的性能差异又往往是非常大的?/p>
以下是三D运行结果完全相同的代码Q它们的作用是在|页中创Z?10x1000 的表根{然而它们的q行速度却有着天壤之别?/p>
- /* 试代码 1 - 耗时 : 41 U?nbsp;*/
- var table = document.createElement("TABLE");
- document.body.appendChild(table);
- for(var i = 0; i < 1000; i++){
- var row = table.insertRow(-1);
- for(var j = 0; j < 10; j++){
- var cell = objRow.insertCell(-1);
- cell.innerText = "( " + i + " , " + j + " )";
- }
- }
- /* 试代码 2 - 耗时 : 7.6 U?nbsp;*/
- var table = document.getElementById("TABLE");
- document.body.appendChild(table);
- var tbody = document.createElement("TBODY");
- table.appendChild(tbody);
- for(var i = 0; i < 1000; i++){
- var row = document.createElement("TR");
- tbody.appendChild(row);
- for(var j = 0; j < 10; j++){
- var cell = document.createElement("TD");
- row.appendChild(cell);
- cell.innerText = "( " + i + " , " + j + " )";
- }
- }
- /* 试代码 3 - 耗时 : 1.26 U?nbsp;*/
- var tbody = document.createElement("TBODY");
- for(var i = 0; i < 1000; i++){
- var row = document.createElement("TR");
- for(var j = 0; j < 10; j++){
- var cell = document.createElement("TD");
- cell.innerText = "( " + i + " , " + j + " )";
- row.appendChild(cell);
- }
- tbody.appendChild(row);
- }
- var table = document.getElementById("TABLE");
- table.appendChild(tbody);
- document.body.appendChild(table);
q里?#8220;试代码 1 ”?#8220;试代码 2 ”之间的差别在于在创徏表格单元时用了不同?API Ҏ(gu)。?#8220;试代码 2 ”?#8220;试代码 3 ” 之间的差别在于处理顺序的略微不同?/p>
“试代码 1 ”?#8220;试代码 2 ”之间如此大的性能差别我们无从分析Q目前所知的?insertRow ?insertCell ?DHTML 中表格特有的 API Q?createElement ?appendChild ?W3C DOM 的原?API 。而前者应该是对后者的装。不q,我们q不能因此而得出结?DOM 的原?API L优于对象Ҏ(gu)?API 。徏议大家在需要频J调用某一 API Ӟ对其性能表现做一些基本的试?/p>
“试代码 2 ”?#8220;试代码 3 ”之间的性能差异主要来自于他们的构徏序不同?#8220;试代码 2 ”的做法是首先创徏最外层?<TABLE> 对象Q然后再在@环中依次创徏 <TR> ?<TD> 。?#8220;试代码 3 ”的做法是首先在内存中由内到外的构建好整个表格Q最后再它d到网中。这样做的目的是可能的减少览器重新计页面布局的次数。每当我们将一个对象添加到|页中时Q浏览器都会试寚w面中的控件的布局q行重新计算。所以,如果我们能够首先在内存中整个要构造的对象全部创徏好,然后再一ơ性的d到网中。那么,览器将只会做一ơ布局的重计算 。ȝZ句话那就是越晚执?appendChild 好。有时ؓ了提高运行效率,我们甚至可以考虑先?removeChild 已存在的控件从面中移除,然后构造完成后再重新将其放|回面当中?/p>
<!-- [if !supportLists]-->n <!-- [endif]-->提高字符串篏加的速度
在?AJAX 提交信息Ӟ我可能常帔R要拼装一些比较大的字W串通过 XmlHttp 来完?POST 提交。尽提交这样大的信息的做法看v来ƈ不优雅,但有时我们可能不得不面对q样的需求。那?JavaScript 中对字符串的累加速度如何呢?我们先来做下面的q个实验。篏加一个长度ؓ 30000 的字W串?/p>
- /* 试代码 1 - 耗时 : 14.325 U?nbsp;*/
- var str = "";
- for (var i = 0; i < 50000; i++) {
- str += "xxxxxx";
- }
q段代码耗时 14.325 U,l果q不理想。现在我们将代码改ؓ如下的Ş式:
- /* 试代码 2 - 耗时 : 0.359 U?nbsp;*/
- var str = "";
- for (var i = 0; i < 100; i++) {
- var sub = "";
- for (var j = 0; j < 500; j++) {
- sub += "xxxxxx";
- }
- str += sub;
- }
q段代码耗时 0.359 U!同样的结果,我们做的只是首先D一些较?yu)的字符串然后再l装成更大的字符丌Ӏ这U做法可以有效的在字W串D的后期减内存复制的数据量。知道了q一原理之后我们q可以把上面的代码进一步拆散以后进行测试。下面的代码仅耗时 0.140 U?/p>
- /* 试代码 3 - 耗时 : 0.140 U?nbsp;*/
- var str = "";
- for (var i1 = 0; i1 < 5; i1++) {
- var str1 = "";
- for (var i2 = 0; i2 < 10; i2++) {
- var str2 = "";
- for (var i3 = 0; i3 < 10; i3++) {
- var str3 = "";
- for (var i4 = 0; i4 < 10; i4++) {
- var str4 = "";
- for (var i5 = 0; i5 < 10; i5++) {
- str4 += "xxxxxx";
- }
- str3 += str4;
- }
- str2 += str3;
- }
- str1 += str2;
- }
- str += str1;
- }
不过Q上面这U做法也许ƈ不是最好的Q如果我们需要提交的信息?XML 格式的(其实l大多数情况下,我们都可以设法将要提交的信息l装?XML 格式Q,我们q能扑ֈ更高效更优雅的方?— 利用 DOM 对象为我们组装字W串。下面这D代买组装一个长度ؓ 950015 的字W串仅须耗时 0.890 U?/p>
- /* 利用 DOM 对象l装信息 - 耗时 : 0.890 U?nbsp;*/
- var xmlDoc;
- if (browserType == BROWSER_IE) {
- xmlDoc = new ActiveXObject("Msxml.DOMDocument");
- }
- else {
- xmlDoc = document.createElement("DOM");
- }
- var root = xmlDoc.createElement("root");
- for (var i = 0; i < 50000; i++) {
- var node = xmlDoc.createElement("data");
- if (browserType == BROWSER_IE) {
- node.text = "xxxxxx";
- }
- else {
- node.innerText = "xxxxxx";
- }
- root.appendChild(node);
- }
- xmlDoc.appendChild(root);
- var str;
- if (browserType == BROWSER_IE) {
- str = xmlDoc.xml;
- }
- else {
- str = xmlDoc.innerHTML;
- }
- <!-- [if !supportLists]-->n
<!-- [endif]-->避免 DOM 对象的内存泄漏?/p>
关于 IE ?DOM 对象的内存泄露是一个常常被开发h员忽略的问题。然而它带来的后果却是非怸重的Q它会导?IE 的内存占用量持箋上升Qƈ且浏览器的整体运行速度明显下降。对于一些泄露比较严重的|页Q甚臛_要刷新几ơ,q行速度׃降低一倍?/p>
比较常见的内存泄漏的模型?#8220; 循环引用 模型”?#8220; 闭包函数 模型”?#8220; DOM 插入序模型” , 对于前两U泄漏模型,我们都可以通过在网|构时解除引用的方式来避免。而对?#8220; DOM 插入序模型”则需要通过改变一些惯有的~程习惯的方式来避免?/p>
有关内存泄漏的模型的更多介绍可以通过 Google 很快的查刎ͼ本文不做q多的阐q。不q,q里我向(zhn)推荐一个可用于查找和分析网内存泄露的工?— Drip Q目前的较新版本?0.5 Q下载地址?http://outofhanwell.com/ieleak/index.php
<!-- [if !supportLists]-->n <!-- [endif]-->复杂面的分D装载和初始?/p>
对系l当中某些确实比较复杂而又不便使用 IFrame 的界面,我们可以对其实施分段装蝲。例如对于多|{界面Q我们可以首先下载和初始化多|{默认,然后利用 AJAH Q?asynchronous JavaScript and HTML Q技术来异步的装载其他标{N中的内容。这样就能保证界面可以在W一旉首先展现l用戗把整个复杂界面的装载过E分散到用户的操作过E当中?/p>
<!-- [if !supportLists]-->n <!-- [endif]-->利用 GZIP 压羃|络量?/p>
除了上面提到的这些代码的改良之外,我们q可以利?GZIP 来有效的降低|络量。目前常见的L览器已l全部支?GZIP 法Q我们往往只需要编写少量的代码可以支?GZIP 了。例如在 J2EE 中我们可以在 Filter 中通过下面的代码来判断客户端浏览器是否支持 GZIP 法Q然后根据需要利?java.util.zip.GZIPOutputStream 来实?GZIP 的输出?/p>
- /* 判断览器对 GZIP 支持方式的代?nbsp;*/
- private static String getGZIPEncoding(HttpServletRequest request) {
- String acceptEncoding = request.getHeader("Accept-Encoding");
- if (acceptEncoding == null) return null;
- acceptEncodingacceptEncoding = acceptEncoding.toLowerCase();
- if (acceptEncoding.indexOf("x-gzip") >= 0) return "x-gzip";
- if (acceptEncoding.indexOf("gzip") >= 0) return "gzip";
- return null;
- }
一般而言Q?GZIP 对于 HTML ?JSP 的压~比可以辑ֈ 80% 左右Q而它造成的服务端和客L的性能损耗几乎是可以忽略的。结合其他因素,支持 GZIP 的网站有可能为我们节U?50% 的网l流量。因?GZIP 的用可以ؓ那些|络环境不是特别好的应用带来显著的性能提升。?Http 的监视工?Fiddler 可以方便的检出|页在?GZIP 前后的通讯数据量?Fiddler 的下载地址?http://www.fiddlertool.com/fiddler/
关于 Web 应用的性能优化其实是一个非常大的话题。本文由于篇q有限,只能涉及其中的几个细节,q且也无法将q些l节的优化方式全面的展现l大家。期望本文能够引起大家对 Web 应用其是客L性能优化的充分重视。毕竟服务端~程技巧已为大家熟知多q_在服务端挖掘性能的潜力已l不大了。而在客户端的Ҏ(gu)改进往往能够得到令h惊奇的性能提升?/p>
【编辑推荐?/p>