`
hongyiqiye
  • 浏览: 90199 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Javascript动态生成表格的性能调优

阅读更多

客户端动态输出table数据并展示表格,是web应用中较为常见的工作。对于循环打印输出tr,td本身是一件非常僵硬和暴力的编程办法,再加上最后绑 定元素innerHTML字符流输出,
系统所消耗的性能代价是非常高昂的,如果我们需要展现的数据非常庞大时,那么代价也是成倍的。然而这种动态输出表格的方法是大多数客户端程序员最常用的方 法。那么基于最常用的方法,
如何才能降低性能成本,改善用户体验,快速安全的显示我们所需要的数据呢?
我认为从根本上调优需要从两个方面去考虑。
1:server的数据吐出和client的数据解析。这里涉及的知识点较多,今后再做详细的说明。但是对于较为复杂的xml的数据格式来 说,client的解析应该用xpath寻址和dom内置对象相结合的方法,高速定位。
2:DHTML的优化。包括dom,css,js的优化,也就是MVC(model, view, control)的优化。
这里我们用js动态生成一个table, 构建一个3000行,8列的表格,代码分多个版本,便于清晰的比较每个版本不同的性能消耗。
vision 0.1 【耗时14694ms】
貌似以下的写法是没有任何错误,但是确是最暴力,效率最低,性能消耗最大的写法。对于大量的数据行和列,用for循环拼接元素字符串,最后 innerHTML输出是不可取的。
3000记录页面加载耗时14694毫秒,近15秒。这样的页面数据加载是近乎灾难的,应该竭力避免。
<html>
<body>
  <div id="tableDiv"></div>
  <script>
   var maxRow =3000;
   var maxCol = 8;
   var strTbl = "<table border='1'><tbody>";
   var strTbody = '';
   
   for(var i = 0; i < maxRow; i++){
    strTbody +="<tr>";
     for(var j = 0; j < maxCol; j++){
      strTbody += "<td>test</td>";
     }
    strTbody += "</tr>";
   }
   strTbl = strTbody + "</tbody></table>";
   
   var obj = document.getElementById("tableDiv");
   obj.innerHTML = strTbl;
   
  </script>
</body>
</html>

vision 0.2 【耗时3623ms】
这个版本的代码有非常大的改进,采用DOM技术动态添加元素,说明在需要处理展现大量数据的情况下,运用DOM快速定位并添加绑定元素的方法,效率远比拼 接html元素字符串的方法要高许多。
整个页面加载完成所耗的时间为3623毫秒。3000行的记录耗时不到4秒,这个版本的代码结构和编程思路也无可挑剔, 那么这样的加载速度是否可以再快些呢?
<html>
<body>
<script>
  var _table, _tbody, tr, td, text, maxRow, maxCol;
  maxRow = 3000;
  maxCol = 8;
  
  _table = document.createElement("table");
  _table.border = "1";
  _tbody = document.createElement("tbody");
  _table.insertBefore(_tbody, null);
  
  document.body.insertBefore(_table, null);
  for (var i=0; i<maxRow; i++) {
  tr = document.createElement("tr");
  for(var j = 0; j<maxCol; j++){
   td = document.createElement("td");
   text = document.createTextNode("Text");
   td.insertBefore(text, null);
   tr.insertBefore(td, null);
  }
     _tbody.insertBefore(tr, null);
  }
</script>
</body>
</html>

vision 0.3 【耗时3320ms】
基于vision 0.2中的代码,我们可以看到,整个代码段有多处用到了"body","window","document"这样的对象,在js中类似这样的对象都为全 局对象,对他们的引用操作势必会消耗性能,
对这些全局变量引用要比简单通过局部变量引用的代价要昂贵的多。
这里我们可以将"document.body"的引用缓存到局部变量中,这样就完成了一个将全局对象转换成局部变量的过程。
在代码中添加:var docBody = document.body;并且将行:document.body.insertBefore(_table, null);替换为:docBody.insertBefore(_table, null);
在代码中对"document"单个全局对象的引用就达到8×3000=24000次之多,获取一个document变量比局部变量大约多花费4ms时 间, 所以我们下一步把document对象也缓存起来。
在代码中添加:var _doc = document;
这样,我们重新加载页面,所耗时间为3320毫秒。只比上个版本所耗的时间减少了10%,似乎性能相差不大,但是在我们日常的开发习惯中,将全局的对象缓 存到局部变量中是一个好的开始。
<html>
<body>
<script>
  var _table, _tbody, tr, td, text, maxRow, maxCol;
  var docBody = document.body;
  var _doc = document;
  maxRow = 3000;
  maxCol = 8;
  
  _table = _doc.createElement("table");
  _table.border = "1";
  _tbody = _doc.createElement("tbody");
  _table.insertBefore(_tbody, null);
  
  docBody.insertBefore(_table, null);
  for (var i=0; i<maxRow; i++) {
  tr = _doc.createElement("tr");
  for(var j = 0; j<maxCol; j++){
   td = _doc.createElement("td");
   text = _doc.createTextNode("Text");
   td.insertBefore(text, null);
   tr.insertBefore(td, null);
  }
     _tbody.insertBefore(tr, null);
  }
</script>
</body>
</html>

vision 0.4 【耗时2779ms】
一个document对象加载速度的优化就是在<script>标签指定defer属性。首先在这里简单介绍一下defer属性。defer 作用是文档加载完毕了再执行脚本,这样回避免找不到对象的问题,
加上defer等于在页面完全在入后再执行,相当于window.onload,但应用上比window.onload 更灵活。设置这个属性仅适合不需要立即运行<SCRIPT>中代码的情况。
(立即运行的代码指不在函数体内的--这些代码将会在脚本块加载后立即执行)当defer属性设置后,IE不会等待加载和转换这段脚本。这就也为着页面加 载会快很多。
通常这意味着立即运行的脚本应该封装放在一个函数内,并通过document或者body的onload的事件处理。如果你的脚本是依赖于页面加载后的用 户动作,如点击按钮,或者移动鼠标到某个区域,会更加有用!
最后请注意两点:
1、不要在defer型的脚本程序段中调用document.write命令,因为document.write将产生直接输出效果。
2、不要在defer型脚本程序段中包括任何立即执行脚本要使用的全局变量或者函数。
<html>
<body onload="init()">
<script defer>
function init() {
  var _table, _tbody, tr, td, text, maxRow, maxCol;
  var docBody = document.body;
  var _doc = document;
  maxRow = 3000;
  maxCol = 8;
  
  _table = _doc.createElement("table");
  _table.border = "1";
  _tbody = _doc.createElement("tbody");
  _table.insertBefore(_tbody, null);
  
  docBody.insertBefore(_table, null);
  for (var i=0; i<maxRow; i++) {
  tr = _doc.createElement("tr");
  for(var j = 0; j<maxCol; j++){
   td = _doc.createElement("td");
   text = _doc.createTextNode("Text");
   td.insertBefore(text, null);
   tr.insertBefore(td, null);
  }
     _tbody.insertBefore(tr, null);
  }
}
</script>
</body>
</html>

vision 0.5 【耗时2650ms】
上一个版本中的页面加载速度已经缩短到了2779ms。下面我们对代码进行进一步的优化。
我们看到代码中dom操作,绑定子元素的方法是由下至上包裹,这样的元素绑定方式会相对较慢。
  create <TR>
  create <TD>
  create TextNode
第一步 insert TextNode into <TD>
第二步 insert <TD> into <TR>
第三步 insert <TR> into TBODY

现在我们将元素的绑定顺序颠倒过来,由上至下的包裹绑定元素
  create <TR>
  create <TD>
  create TextNode
第一步 insert <TR> into TBODY
第二步 insert <TD> into <TR>
第三步 insert TextNode into <TD>
<html>
<body onload="init()">
<script defer>
function init() {
  var _table, _tbody, tr, td, text, maxRow, maxCol;
  var docBody = document.body;
  var _doc = document;
  maxRow = 3000;
  maxCol = 8;
  
  _table = _doc.createElement("table");
  _table.border = "1";
  _tbody = _doc.createElement("tbody");
  _table.insertBefore(_tbody, null);
  docBody.insertBefore(_table, null);
  
  for (var i=0; i<maxRow; i++) {
  tr = _doc.createElement("tr");
   _tbody.insertBefore(tr, null);
  for(var j = 0; j<maxCol; j++){
   td = _doc.createElement("td");
   text = _doc.createTextNode("Text");
   td.insertBefore(text, null);
   tr.insertBefore(td, null);
  }
  }
}
</script>
</body>
</html>

vision 0.6 【耗时2580ms】
这个版本中我们要调优的是修改table的css属性,使用fixed-table布局(layout)。指定了fixed-table布局后的表格的列 宽使用<col>标签设置。
fixed-table布局样式将改善table的性能,因为每个单元格的内容的尺寸不需要进行计算了。这是一个非常实用的性能改善方法,特别是那些有很 多列的大型表格。
这个操作也可以通过简单增加css样式实现:
<html>
<body onload="init()">
<script defer>
function init() {
  var _table, _tbody, tr, td, text, maxRow, maxCol;
  var docBody = document.body;
  var _doc = document;
  maxRow = 3000;
  maxCol = 8;
  
  _table = _doc.createElement("table");
  _table.border = "1";
  _table.style.tableLayout = "fixed";
  _tbody = _doc.createElement("tbody");
  _table.insertBefore(_tbody, null);
  docBody.insertBefore(_table, null);
  
  for (var i=0; i<maxRow; i++) {
  tr = _doc.createElement("tr");
   _tbody.insertBefore(tr, null);
  for(var j = 0; j<maxCol; j++){
   td = _doc.createElement("td");
   text = _doc.createTextNode("Text");
   td.insertBefore(text, null);
   tr.insertBefore(td, null);
  }
  }
}
</script>
</body>
</html>

vision 0.7 【耗时2210ms】
最后的一个版本的调优就是给单元格赋值的方式。在所有的示例中,创建了一个TextNode,并添加给TD。而在这个版本中我们将使用innerText 代替插入一个text节点,代码调整为:
td.innerText = "Text";
(注意:innerText只在IE中受支持,属于IE扩展,兼容FireFox可使用innerHTML,但是innerHTML正如文章开头所说的, 效率非常低下,不建议使用)
<html>
<body onload="init()">
<script defer>
  function init() {
  var _table, _tbody, tr, td, text, maxRow, maxCol;
  var docBody = document.body;
  var _doc = document;
  maxRow = 3000;
  maxCol = 8;
  
  _table = _doc.createElement("table");
  _table.border = "1";
  _table.style.tableLayout = "fixed";
  _tbody = _doc.createElement("tbody");
  
  docBody.insertBefore(_table, null);
  _table.insertBefore(_tbody, null);
  
  for (var i=0; i<maxRow; i++) {
  tr = _doc.createElement("tr");
   _tbody.insertBefore(tr, null);
  for(var j = 0; j<maxCol; j++){
   td = _doc.createElement("td");
   td.innerText = "Text";
   tr.insertBefore(td, null);
  }
  }
}
</script>
</body>
</html>

vision 0.8 【耗时672ms】终极优化
将字符串作为数组对象的方式是目前效率最高,性能最优的方式。
<script>
var t1 = new Date();
</script>
<html>
<head>
  <title></title>
  <script>
   function testTime(){
    var t2 = new Date();
    alert(t2-t1+"ms");
   }
   
  </script>
  
</head>
<body onload="init();testTime();">
  <div id="tableDiv"></div>
  <script>
   var maxRow =3000;
   var maxCol = 8;
   var strTbody = ["<table border='1'><tbody>"];
   
   for(var i = 0; i < maxRow; i++){
    strTbody.push("<tr>");
     for(var j = 0; j < maxCol; j++){
      strTbody.push("<td>test</td>");
     }
    strTbody.push("</tr>");
   }
   
   strTbody.push("</tbody></table>");
   
   var obj = document.getElementById("tableDiv");
   obj.innerHTML = strTbody.join("");
  </script>
</body>
</html>

分享到:
评论

相关推荐

    JAVA+JSP

    - **JSP展示**:通过JSP动态生成表格显示课程列表和学生成绩,利用EL(Expression Language)和JSTL(JavaServer Pages Standard Tag Library)简化页面逻辑。 - **用户交互**:利用HTML表单和JavaScript进行用户...

    Actuate--administering-iserver-system.pdf

    以上内容涵盖了 Actuate iServer 系统的主要方面,包括系统架构、安装配置、报表设计、性能调优及第三方集成等方面的知识点。通过这些内容的学习,可以帮助 IT 专业人士更好地理解和掌握 Actuate iServer 的使用方法...

    GWT入门和进阶

    性能调优** 学习如何分析GWT应用的性能瓶颈,使用开发工具中的Profiler模块进行内存和CPU性能分析。 通过以上介绍,我们可以看到GWT不仅提供了一套完整的开发工具链,还有一系列高级特性和最佳实践,使得开发者...

    GridViewPrint(小、简单易用)

    此外,数据库的性能调优也是关键,确保大数据量时快速响应,为前端展示提供流畅体验。 总结: GridViewPrint是一个实用的工具,帮助开发者轻松实现ASP.NET GridView的打印功能,而无需复杂的后端和前端代码。通过...

    时尚购物网站工程源码(带数据库)

    - 实践项目部署,学习如何将代码部署到服务器并进行性能调优。 总的来说,这是一个全面的项目,适合想要提升网站开发技能的初学者或开发者。通过实际操作和研究,你可以深入理解网站开发的全过程,对你的编程生涯...

    成为一个成功Jsp程序员的九步

    5. **深化Web服务器知识**:理解Web服务器的高级特性,例如错误处理、日志记录和性能调优,这将花费2天左右。 6. **建立JSP服务器**:安装并熟悉JSP服务器,如Tomcat,它是一个轻量级且广泛使用的服务器。安装过程...

    html2canvas.js和jspdf.debug.js.rar

    JSPDF支持多种字体、图像、表格和文本格式,可以方便地将网页内容、用户生成的数据或者图表导出为PDF。它还提供了API接口,可以自定义PDF的布局和样式。例如,你可以通过合并HTML2canvas.js与jspdf.debug.js,先将...

    巴音郭楞职业技术学院迎新工作管理系统的设计与实现-软件工程专业论文.docx

    - **性能调优**:针对测试中发现的问题进行性能调优。 - **用户体验改进**:根据用户反馈优化界面布局和交互流程。 ### 六、总结与展望 巴音郭楞职业技术学院迎新工作管理系统的成功开发,不仅提高了迎新工作的...

    学生信息管理系统

    此外,系统的性能优化也是不可忽视的一环,可能需要进行数据库索引优化、缓存策略设置、JVM调优等措施,以确保在大量数据和高并发场景下依然能保持良好的运行性能。 总的来说,学生信息管理系统通过整合jQuery、...

    ICE face 開發指南

    4. **性能调优**:提供性能优化的最佳实践,包括如何有效利用PPR,减少网络请求,以及如何进行组件级优化。 5. **错误处理和调试**:指导如何调试ICEface 应用,处理可能出现的错误和异常,以及如何查看和理解日志...

    网上书店--JSP+MySql

    通过这个项目,开发者可以深入理解和实践Web应用开发的各个环节,掌握JSP、Servlet和数据库的综合运用,同时对Web安全和性能调优有所了解。此外,项目经验对于提升实际项目开发能力和团队协作能力也有很大帮助。

    dorado7离线中文文档.7z

    9. **性能优化**:提供性能调优的最佳实践和技巧,确保应用运行高效。 10. **调试和测试**:指导如何使用 Dorado 的调试工具和测试框架进行应用的测试和调试。 11. **最佳实践**:分享开发过程中的经验和技巧,帮助...

    史上最好传智播客就业班.net培训教程60G 不下会后悔

    不是直接教学员怎么拖ASP.Net控件进行快速开发,而是通过ashx的模式开发原始的动态网站,让学员明白“请求—处理—响应模型”、“Http协议、Http无状态”、“c#代码渲染生成浏览器端JavaScript”、“ViewState的作用...

    DbVisualizer 9.2.15

    提供执行计划分析和SQL调优工具,帮助用户识别和解决性能瓶颈,提升数据库性能。 10. **源码控制集成**: 与Git、SVN等版本控制系统集成,允许用户版本化SQL脚本,协同开发更高效。 11. **宏和脚本支持**: ...

    数据库大作业.zip

    7. **性能监控与调优**:通过监控数据库性能,可以识别潜在瓶颈并进行优化。这可能包括调整查询语句、增加硬件资源或者调整数据库参数。 8. **报表和数据分析**:图书馆管理系统可能需要生成各种报表,如最常借阅的...

    loam_velodyne-master _loam源码_sortTABLEjs官网_loam_loam_velodyne_lo

    通过这个工具,开发者可以更方便地对算法性能进行评估和调优。 四、Loam算法核心原理 1. 特征提取:Loam首先从每一帧的点云中提取稳定的边缘和平面特征,这些特征对环境变化不敏感,适合于定位和匹配。 2. 匹配与...

    CovidTracker:收集来自covid api的covid案例的总数,活动,已故和已恢复的covid案例,并将其显示在基于django的webapp上

    3. **优化**:针对高并发场景,可以使用Gunicorn或uWSGI等WSGI服务器部署Django应用,同时考虑数据库查询优化和代码性能调优。 总结,CovidTracker项目展示了如何利用Python和Django框架来创建一个实时的COVID-19...

    AssignmentPracticalMachineLearning:在Coursera上进行实用机器学习课程的作业

    3. JavaScript文件:可能包含与用户交互有关的脚本,例如处理表单提交、动态更新预测结果等。 4. 数据文件:可能是CSV或JSON格式,包含用于训练机器学习模型的数据集。 5. Python或R脚本:用于数据预处理、模型训练...

    Structured Web Data Extraction 数据集数据集

    1. 预处理:清洗和标准化HTML,处理JavaScript生成的内容。 2. 特征工程:提取有意义的特征,如HTML标签、属性、CSS类等。 3. 模型构建:使用传统的规则方法、模板匹配、机器学习模型或深度学习模型。 4. 训练与调优...

Global site tag (gtag.js) - Google Analytics