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


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 相关文章推荐
JavaScript 一行代码,轻松搞定浮动快捷留言-V2升级版
Apr 02 Javascript
jQuery.prototype.init选择器构造函数源码思路分析
Feb 05 Javascript
Flex通过JS获取客户端IP和计算机名的实例代码
Nov 21 Javascript
jquery实现tr元素的上下移动示例代码
Dec 20 Javascript
Node.js中使用事件发射器模式实现事件绑定详解
Aug 15 Javascript
解决js下referer兼容各大浏览器的方法
Nov 03 Javascript
node.js中的buffer.copy方法使用说明
Dec 14 Javascript
浅析webapp框架AngularUI的demo
Dec 21 Javascript
用js实现博客打赏功能
Oct 24 Javascript
vue.js通过路由实现经典的三栏布局实例代码
Jul 08 Javascript
Node.js实现简单的爬取的示例代码
Jun 25 Javascript
vue实现拖拽进度条
Mar 01 Vue.js
对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
php in_array 函数使用说明与in_array需要注意的地方说明
2010/04/13 PHP
zf框架的zend_cache缓存使用方法(zend框架)
2014/03/14 PHP
php使用curl和正则表达式抓取网页数据示例
2014/04/13 PHP
php找出指定范围内回文数且平方根也是回文数的方法
2015/03/23 PHP
jquery validator 插件增加日期比较方法
2010/02/21 Javascript
js文本框输入点回车触发确定兼容IE、FF等
2013/11/19 Javascript
javascript写的异步加载js文件函数(支持数组传参)
2014/06/07 Javascript
利用原生JavaScript获取元素样式只是获取而已
2014/10/08 Javascript
CSS3,HTML5和jQuery搜索框集锦
2014/12/02 Javascript
9款2014最热门jQuery实用特效推荐
2014/12/07 Javascript
JS实现横向与竖向两个选项卡Tab联动的方法
2015/09/27 Javascript
pace.js页面加载进度条插件
2015/09/29 Javascript
Bootstrap Table从服务器加载数据进行显示的实现方法
2016/09/29 Javascript
jquery Ajax实现Select动态添加数据
2017/06/08 jQuery
微信小程序--组件(swiper)详细介绍
2017/06/13 Javascript
webpack学习--webpack经典7分钟入门教程
2017/06/28 Javascript
nodejs前端自动化构建环境的搭建
2017/07/26 NodeJs
jQuery实现当拉动滚动条到底部加载数据的方法分析
2019/01/24 jQuery
js实现QQ邮箱邮件拖拽删除功能
2020/08/27 Javascript
Python实现的生成自我描述脚本分享(很有意思的程序)
2014/07/18 Python
Centos Python2 升级到Python3的简单实现
2016/06/21 Python
python根据unicode判断语言类型实例代码
2018/01/17 Python
浅谈flask中的before_request与after_request
2018/01/20 Python
Python Pandas批量读取csv文件到dataframe的方法
2018/10/08 Python
解决python写入带有中文的字符到文件错误的问题
2019/01/31 Python
python encrypt 实现AES加密的实例详解
2020/02/20 Python
使用 django orm 写 exists 条件过滤实例
2020/05/20 Python
Python在后台自动解压各种压缩文件的实现方法
2020/11/10 Python
python UDF 实现对csv批量md5加密操作
2021/01/01 Python
Reformation官网:美国女装品牌
2018/09/14 全球购物
俄罗斯电子产品、计算机和家用电器购物网站:OLDI
2019/10/27 全球购物
乌克兰数字设备、配件和智能技术的连锁商店:KTC
2020/08/18 全球购物
2016年师德先进个人事迹材料
2016/02/29 职场文书
你会写请假条吗?
2019/06/26 职场文书
导游词之麻姑仙境
2019/11/18 职场文书
python游戏开发Pygame框架
2022/04/22 Python