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


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,Extjs,YUI,Prototype,Dojo 等JS框架的区别和应用场景简述
Apr 15 Javascript
全面兼容的javascript时间格式化函数(比较实用)
May 14 Javascript
一款基于jQuery的图片场景标注提示弹窗特效
Jan 05 Javascript
JS实现网页滚动条感应鼠标变色的方法
Feb 26 Javascript
javascript使用Promise对象实现异步编程
Mar 01 Javascript
轻松实现jquery选项卡切换效果
Oct 10 Javascript
用jmSlip编写移动端顶部日历选择控件
Oct 24 Javascript
vuex实现简易计数器
Oct 27 Javascript
详解vue组件开发脚手架
Jun 15 Javascript
微信小程序实现笑脸评分功能
Nov 03 Javascript
小程序实现左右来回滚动字幕效果
Dec 28 Javascript
vuex分模块后,实现获取state的值
Jul 26 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
一个简单的瀑布流效果(主体形式自写)
2013/05/27 Javascript
JS中的数组的sort方法使用示例
2014/01/22 Javascript
一个JS函数搞定网页标题(title)闪动效果
2014/05/13 Javascript
node.js中的fs.lchmod方法使用说明
2014/12/16 Javascript
几种经典排序算法的JS实现方法
2016/03/25 Javascript
jquery自定义插件开发之window的实现过程
2016/05/06 Javascript
Bootstrap学习系列之使用 Bootstrap Typeahead 组件实现百度下拉效果
2016/07/07 Javascript
javascript 动态样式添加的简单实现
2016/10/11 Javascript
JavaScript for循环 if判断语句(学习笔记)
2017/10/11 Javascript
如何让你的JS代码更好看易读
2017/12/01 Javascript
Vue2 模板template的四种写法总结
2018/02/23 Javascript
vue slot 在子组件中显示父组件传递的模板
2018/03/02 Javascript
react实现点击选中的li高亮的示例代码
2018/05/24 Javascript
layui数据表格跨行自动合并的例子
2019/09/02 Javascript
浅谈layui 表单元素的选中问题
2019/10/25 Javascript
小程序实现背景音乐播放和暂停
2020/06/19 Javascript
如何构建 vue-ssr 项目的方法步骤
2020/08/04 Javascript
Python自动登录126邮箱的方法
2015/07/10 Python
python变量不能以数字打头详解
2016/07/06 Python
详解Golang 与python中的字符串反转
2017/07/21 Python
python多线程之事件Event的使用详解
2018/04/27 Python
python操作文件的参数整理
2019/06/11 Python
Python高级property属性用法实例分析
2019/11/19 Python
python实现超级玛丽游戏
2020/03/18 Python
h5使用canvas画布实现手势解锁
2019/01/04 HTML / CSS
GoPro摄像机美国官网:美国运动相机厂商
2018/07/03 全球购物
世界排名第一的运动鞋市场:Flight Club
2020/01/03 全球购物
学校节能减排倡议书
2014/05/16 职场文书
2014年平安建设工作总结
2014/11/19 职场文书
2014年电话客服工作总结
2014/12/09 职场文书
酒店服务员岗位职责
2015/02/09 职场文书
2015年妇委会工作总结
2015/05/22 职场文书
Nginx 根据URL带的参数转发的实现
2021/04/01 Servers
详解nginx安装过程并代理下载服务器文件
2022/02/12 Servers
vue3获取当前路由地址
2022/02/18 Vue.js
mysql 索引的数据结构为什么要采用B+树
2022/04/26 MySQL