提高代码性能技巧谈—以创建千行表格为例


Posted in Javascript onJuly 01, 2006

微软的开发周期中很重要的一块是调整产品的性能。性能调整也是开发者应当留心的关键部分之一。 经过多年发展,业界对于如何优化Win32程序性能已经有非常多的了解。

现在开发者遇到的问题之一是不太清楚是什么导致DTHML和HTML页面运行快或者慢。当然,有一些很简单的方法——比如不要使用2MB大的图片。我们曾经使用过另外一些有趣的技巧提高了DHTML页面的性能,希望它们能帮助你改善自己的页面性能。

这里我使用了一个建立Table的程序例子。其中用document.createElement()和element.insertBefore()方法创建了1000行(Row)的表(Table)。每行有一列(Cell)。Cell中包含的内容称为"Text"。这段代码能有多糟呢?这么小的程序又能有多大调整余地呢?请看介绍。

一开始我写了一段自认为会很快的程序,我尽量避免一些低级问题----像没有显式定义变量、或者在一个页面中同时使用VBScript和Javascript。程序如下:

<html>
<body>
<script>
var tbl, tbody, tr, td, text, i, max;
max = 1000;

tbl = document.createElement("TABLE");
tbl.border = "1";
tbody = document.createElement("TBODY");
tbl.insertBefore(tbody, null);
document.body.insertBefore(tbl, null);
for (i=0; i<max; i++) {
tr = document.createElement("TR");
td = document.createElement("TD");
text = document.createTextNode("Text");
td.insertBefore(text, null);
tr.insertBefore(td, null);
tbody.insertBefore(tr, null);
}
</script>
</body>
</html>

在PII233/64MB内存/NT4.0/IE5.0的机器上运行这段程序。页面从本机上装载。从开始装载页面到页面完全安静下来(所有的事件均已经运行,屏幕显示完成)的时间为2328毫秒,这也是本次测试的基线(我称之为Test1)。

这个页面中,一个很耗时的操作是频繁引用全局对象,如“document”、“body”、“window”等。引用所有这些类似的全局变量远比引用一个本地变量代价高昂。

因此我作了第一次改进尝试:缓存(Cache)document.body 到本地变量“theBody”中:

增加了如下代码:

var theBody = document.body;
然后修改这一行:

document.body.insertBefore(tbl, null);
将之改为:

theBody.insertBefore(tbl, null);
View the second sample.

这次修改并没有太大影响到整体时间,它只缩短了3 ms。但它已经表明,如果在循环中也有document.body对象而对其引用做出修改,带来的好处将是可观的。

随后,我缓存了document对象----在我们这个测试中,document对象共被引用了3002次。修改后代码如下:

<html>
<body>
<script>
var tbl, tbody, tr, td, text, i, max;
max = 1000;
var theDoc = document;
var theBody = theDoc.body;

tbl = theDoc.createElement("TABLE");
tbl.border = "1";
tbody = theDoc.createElement("TBODY");
tbl.insertBefore(tbody, null);
theBody.insertBefore(tbl, null);
for (i=0; i<max; i++) {
tr = theDoc.createElement("TR");
td = theDoc.createElement("TD");
text = theDoc.createTextNode("Text");
td.insertBefore(text, null);
tr.insertBefore(td, null);
tbody.insertBefore(tr, null);
}
</script>
</body>
</html>
View the third sample.

此次运行时间只有2100ms,节约了大约10%的时间。使用本地变量而不是直接引用document对象平均每次节约了0.4毫秒。

一个常用的优化性能的方法是:当脚本不需要立即运行时,在<SCRIPT>标签中设置“defer”属性。 (立即脚本没有被包含在一个function块中,因此会在加载过程中执行。) 设置“defer”属性后,IE就不必等待该脚本装载和执行完毕。这样页面加载会更快。一般来说,这也表明立即脚本最好放在function块中,并在document或者body对象的onload 句柄中处理该函数。在有一些脚本需要依赖用户操作而执行时----例如点击按钮,或者移动鼠标到某个区域----使用该属性非常有用。但当有一些脚本需要在页面加载过程中或加载完成后执行,使用defer属性得到的好处就不太大。

下面是使用了defer属性修改后的代码版本:

<html>
<body onload="init()">
<script defer>
function init() {
var tbl, tbody, tr, td, text, i, max;
max = 1000;
var theDoc = document;
var theBody = theDoc.body;

tbl = theDoc.createElement("TABLE");
tbl.border = "1";
tbody = theDoc.createElement("TBODY");
tbl.insertBefore(tbody, null);
theBody.insertBefore(tbl, null);
for (i=0; i<max; i++) {
tr = theDoc.createElement("TR");
td = theDoc.createElement("TD");
text = theDoc.createTextNode("Text");
td.insertBefore(text, null);
tr.insertBefore(td, null);
tbody.insertBefore(tr, null);
}
}
</script>
</body>
</html>
View the fourth sample.

这次测试的时间为2043 ms。相对基线测试提高了12%,比上次测试提高了2.5%。

下面我们谈到的一个改进方法非常有用,当然也稍微麻烦一点。当需要创建元素然后将其插入树状的结构中时,将其直接插入到主干中效率更高----而不是首先将其插入大的子树,然后再将大的子树插入主干。例如,如果你创建一个每行有一列、列中有一些文字的表,你可以这样做:

1. 创建<TR>

2. 创建<TD>

3. 创建TextNode节点

4. 将TextNode 插入<TD>

5. 将<TD> 插入到 <TR>

6. 将<TR>插入到TBODY

当它要比下面的方法慢一些:

1. 创建<TR>

2. 创建<TD>

3. 创建TextNode

4. 将<TR> 插入到TBODY

5. 将<TD> 插入到<TR>

6. 将TextNode插入到<TD>

上面的四次测试使用的都是前一种方法。我们用后一种方法进行第5次测试。代码如下:

<html>
<body onload="init()">
<script defer>
function init() {
var tbl, tbody, tr, td, text, i, max;
max = 1000;
var theDoc = document;
var theBody = theDoc.body;

tbl = theDoc.createElement("TABLE");
tbl.border = "1";
tbody = theDoc.createElement("TBODY");
tbl.insertBefore(tbody, null);
theBody.insertBefore(tbl, null);
for (i=0; i<max; i++) {
tr = theDoc.createElement("TR");
td = theDoc.createElement("TD");
text = theDoc.createTextNode("Text");
tbody.insertBefore(tr, null);
tr.insertBefore(td, null);
td.insertBefore(text, null);
}
}
</script>
</body>
</html>
View the fifth sample.

Test5只需1649ms。这比上次测试提高了25%,比基线快了几乎30%。

随后的修改是使用了预制的样式表。使用了预制样式表的表格列宽或者是通过<COL>标签设置,没有<COL>标签时,每列的宽度均匀分布。因为不需要对每一列重新计算大小等,使用样式表实际上提高了性能,尤其当表格中的列数很多时。

增加样式表(CSS)的代码非常简单,如下:

tbl.style.tableLayout = "fixed";
View the sixth sample.

因为我们测试中的表格只有一列,这种改变只提高了页面1.6%的性能。如果有更多的列,性能增加会更多。

最后两次测试改变了将文字插入到表格中的方法。前面的测试中,我们都先创建一个TextNode ,然后将其插入到TD中。在Test7中, 取而代之,我们通过innerText 指定包含的文字。修改的代码是:

td.innerText = "Text";
View the seventh sample.

令人惊奇的是,这次修改产生的差异很大----比上次提高了9%的性能,比最初总共提高了36%的性能。时间从最初的2323ms到最后的1473ms。

现在,几乎人人都知道使用element.innerHTML 非常慢. 为了看看究竟它如何慢,我做了最后一次测试:使用 innerHTML替代innerText插入文字。这大大降低了性能。时间达到3375ms,比上次测试慢了80%,比基线测试慢了45%。显然,innerHTML是非常耗时的。

调整HTML页面性能类似于调整Win32应用程序性能;需要知道什么慢,什么快。希望这些方法能帮你提高页面性能。

Javascript 相关文章推荐
jquery animate 动画效果使用说明
Nov 04 Javascript
javascript 内存回收机制理解
Jan 17 Javascript
jquery的trigger和triggerHandler的区别示例介绍
Apr 20 Javascript
IE6中链接A的href为javascript协议时不在当前页面跳转
Jun 05 Javascript
input标签内容改变的触发事件介绍
Jun 18 Javascript
JavaScript函数参数使用带参数名的方式赋值传入的方法
Mar 19 Javascript
用JavaScript动态建立或增加CSS样式表的实现方法
May 20 Javascript
Vue通过input筛选数据
Oct 26 Javascript
vue2 中如何实现动态表单增删改查实例
Jun 09 Javascript
javascript实现Emrips反质数枚举的示例代码
Dec 06 Javascript
详解vue的双向绑定原理及实现
May 05 Javascript
html-webpack-plugin修改页面的title的方法
Jun 18 Javascript
对textarea框的代码调试,而且功能上使用非常方便,酷
Jun 30 #Javascript
列表内容的选择
Jun 30 #Javascript
会自动逐行上升的文本框
Jun 30 #Javascript
自动检查并替换文本框内的字符
Jun 30 #Javascript
一个很简单的办法实现TD的加亮效果.
Jun 29 #Javascript
网页的标准,IMG不支持onload标签怎么办
Jun 29 #Javascript
父窗口获取弹出子窗口文本框的值
Jun 27 #Javascript
You might like
ThinkPHP缓存方法S()概述
2014/06/13 PHP
浅谈PHP拦截器之__set()与__get()的理解与使用方法
2016/10/18 PHP
php preg_match的匹配不同国家语言实例
2016/12/29 PHP
深入讲解PHP的对象注入(Object Injection)
2017/03/01 PHP
javascript获取当前ip的代码
2009/05/10 Javascript
JavaScript 异步调用框架 (Part 4 - 链式调用)
2009/08/04 Javascript
Javascript 网页黑白效果实现代码(兼容IE/FF等)
2010/04/23 Javascript
基于jquery的页面划词搜索JS
2010/09/14 Javascript
Javascript判断对象是否相等实现代码
2013/03/18 Javascript
javascript简单实现表格行间隔显示颜色并高亮显示
2013/11/29 Javascript
jQuery模仿单选按钮选中效果
2016/06/24 Javascript
JS获取和修改元素样式的实例代码
2016/08/06 Javascript
JS中Array数组学习总结
2017/01/18 Javascript
bootstrap multiselect 多选功能实现方法
2017/06/05 Javascript
基于jQuery实现定位导航位置效果
2017/11/15 jQuery
react 实现页面代码分割、按需加载的方法
2018/04/03 Javascript
Jquery+AJAX实现无刷新上传并重命名文件操作示例【PHP后台接收】
2020/05/29 jQuery
javascript运行机制之执行顺序理解
2020/08/03 Javascript
Python Sqlite3以字典形式返回查询结果的实现方法
2016/10/03 Python
Sanic框架Cookies操作示例
2018/07/17 Python
在keras中model.fit_generator()和model.fit()的区别说明
2020/06/17 Python
Python如何把字典写入到CSV文件的方法示例
2020/08/23 Python
Hotels.com加拿大:领先的在线住宿网站
2018/10/05 全球购物
俄罗斯电动工具和设备购物网站:Vseinstrumenti.ru
2020/11/12 全球购物
电大自我鉴定
2013/10/27 职场文书
关于圣诞节的广播稿
2014/01/26 职场文书
音乐教学反思
2014/02/02 职场文书
党员承诺书格式
2014/05/21 职场文书
质量管理标语
2014/06/12 职场文书
助人为乐道德模范事迹材料
2014/08/16 职场文书
安全环保演讲稿
2014/08/28 职场文书
2014乡镇党委副书记对照检查材料思想汇报
2014/10/09 职场文书
佛光寺导游词
2015/02/10 职场文书
七一慰问简报
2015/07/20 职场文书
解析Java中的static关键字
2021/06/14 Java/Android
一篇带你入门Java垃圾回收器
2021/06/16 Java/Android