JS效率个人经验谈(8-15更新),加入range技巧


Posted in Javascript onJanuary 09, 2007

首先,要谢谢CSDN hbhbhbhbhb1021(天外水火(我要多努力))和cuixiping(无心)的提醒。我会抽空把IE专有的方法如:insertAdjacentHTML的速度也给测出来看看是否合适大量数据时IE下,不用innerHTML的速度。
这里的主要测试不是指生成数据时的速度,指的是匹配速度 ,例如
我这里的匹配速度
我测的10000条数据,有效数据为1000-1100条,输出复杂的HTML,速度为360ms左右,方法为 正则匹配Match(有循环)
希望贴出您的测试数据。
行innerHTML和insertAdjacentHTML速度的测试,比均结果相差不会大于20ms(平均速度),在IE中insertAdjacentHTML速度还是很快的,在Mozilla下是得不偿失的。

JS效率个人经验谈(8-15更新),加入range技巧 可以点击这里进行简单的匹配测试
JS效率个人经验谈(8-15更新),加入range技巧 点击这里进行innerHTML和insertAdjacentHTML速度的测试,可以兼容Mozilla的

写这篇文章,其间我也是删删减减的,所以语句也不怎么通顺,看的朋友也就辛苦了一些了。

本文主要是出于有朋友使用我原来写的autocomplete的JS控件。当数据量大的时候,会出现效率极其慢的情况,我在这段时间做出的一些测试也及一些经验,与大家分享,如果有错的地方,还请指出。

经过测试,我们会发现如下的情况或者说的结论,如果您的测试结果与我的不符,请说明原因,以便相互学习。

1)当一个较大的HTML字符串给到obj.innerHTML时会出现麻烦。也就是说当一个较大的字符串在赋予一个Element的innerHTML时,这个过程将可能是我们无法容忍的。(而事实上这并非JS的错,而确实是String数据量太多)
2)用拼合字符串的方法可以使效率提高,在字符串较大时,2)的情况仍然出现。超过一定的数量,速度会明显慢下来。
3)正则匹配的方法会比平常遍历的方法要高效一些。
4)在执行过程中,绑定事件的时间会花费更多一些。测试在1w条数据情况下,大约是匹配以及生成HTML数据的30倍,也就是说生成数据总花费100ms,而绑定事件则需要3000ms。
5)总体来说。IE的速度要比Mozilla要慢(我用的是Firefox1.5做的测试)。
6)大数据量时,不要用DOM生成Element。
7)非JS内置方法,也许会引发很多时间过多重复的劳动而且可能事得其反。建议尽可能利会内置方法。
总结问题:
一、在把字符串给到innerHTML上。
二、循环绑定事件所花费时间。
三、生成我们需要的DIV所花时间。
四、不同的浏览器问题。

下面对症下药:

问题一

我们可以做的没有其它的,只有尽可能少的HTML字符串,比如最基本的一个DIV,可以这样写
<div style="height:20px; font:9pt Verdana;"></div>也可以这样写<div class="c1"></div>,第二种就比第一种速度明显要快的。如果还不行的话,请看下面这个方法对你是否合适

在做程序的时候突然想起来51js上PK tree,一位版主所写的一棵树,1百万的一个节点,动态载入。只需要不到1秒。毫无疑问,肯定是取巧了,因为只要只生tree的html就是一个很大的数量。这个树的特别的地方就是生成树时,并非把1百万的节点都一次生成innerHTML,而是只生成在视角范围内的节点,当滚动条向下滚的时候,才动态的再生成树节点。这个方法至少我觉得思想很开阔,很有价值。

我们所知道,mySQL数据库里取数据可以这么取。SELECT * FROM table limit 0,100,意思是只取数据库中的0-100条数据。说到这里可能有些朋友也想到了,在JS中,我们可以利用这个方法来取数据,将一个数组看作是一个表。只是单纯的数据表,非二维表。如图

JS效率个人经验谈(8-15更新),加入range技巧

利用这一些,我们可以把数据有效的值先取出来。如图:
JS效率个人经验谈(8-15更新),加入range技巧

想想看。假如我们取一个数组,下标为10000,设生成一个autocomplete的节点HTML长度20(已经非常小了"<div class="out">item</div>)。
匹配数据已知:有3000条数据
输节字节数为:3000(asc码)也就是3000*20=60000字节
而用limit方法,输出为:10*20=200字节。
很明显的差距!
之后我们便可以分步求解,即当滚动条出现,或者按下down(方向键)再动态的生成innerHTML。
8-13更新:测了一下,用自己写的limit的速度,和自带的Array.slice的速度比了一下,速度差不多,而且有的时候还比slice的速度还要快一些。
Array.prototype.limit = function(l, h) {
var _a = this; var ret = [];
l = l<0?0:l; h = h>_a.length?_a.length:h;
for (var i=0; i<_a.length; i++) {
if (i>=l && i<=h) ret[ret.length] = _a[i];
if (i>h) break;
}; return ret;
}
有兴趣的朋友也可以自己测一下,贴出数据,看看哪个效率更好。

问题二、
为什么我们还要循环来绑定事件呢?
还是由于问题一。
假设这样写
1)
<div id="container">
<div onclick="handlerClick()">never-online</div>
</div>
还可以这样写
2)
<div id="container">
<div>never-online</div>
</div>
document.getElementById("container").childNodes[0].onclick=function(){handlerClick()};
这样也可以省掉一些字符串,从而节省字符串资源。但又需要把container的子元素再遍历,所以也会花费时间,用第一种方法还是第二种?我建议还是用第一种,但最好把字符串减到最低,如:
<div id="container">
<div onclick="_c()">never-online</div>
</div>
大数据量情况下,还是越少字符越好,虽然代码不怎么美观。

问题三、
生成DIV时我们可以这样生成
var div = document.createElement("DIV");
div.onclick=function(){};
//TODO
也可以这样用字符串
var sHtml = "<div onclick=foo()>val</div>";
当数量小时,第一种速度会比第二种快。但当达到一个数量级时,第二种要明显比第一种快。总体来说第二种较好。因为第二种还可以更灵活,比如利用join,还有正则匹配。

问题四、
这个问题也不容忽视的。每个browser有不同的特点,速度执行也有不同,我个人觉得,这点和JS上优化效率上是一样的。
尽可能的利用浏览器本身的内置方法,这样大多数情况下也可以把效率提高。

那么如何能够把脚本的效率提高起来呢?
1)用match匹配,一个aCache数组。循环match.length,并给aCache,之后用join(""),再给到innerHTML(此方法仍然需要循环,而且需额外的一个数组做临时数据存储)
2)无需循环,但必须在生成数据时也额外生成指定字符串。(此方法也需要额外的空间做临时数据)如图:

JS效率个人经验谈(8-15更新),加入range技巧

3)宁可多次判断,也不重复进行一次重新匹配。e.g:
input控件中第一次取到的值为:1,第二次按下的值为12
如果进行判断的话,可以事件存储一个值,也就是前一次按下的值。如上面的值1。第二次按下时没有退格,即再在前面的值中加一个字符2,那么我们将在前面1中匹配出的数据中进行匹配。这样可以大大的减轻循环的次数。
4)利用问题一中所写的limit,将数据动态取出。这些能够很好的解决HTML字符串过大的问题,但此方法控制不当的话,也会事得其反。
5) 利用range技巧来加入HTMLStr,也就是说,当一个HTML字符串太大时,再用innerHTML+=anotherHTMLStr,这样的方法,也是会让速度太慢,在IE中,我们可以用obj.insertAdjacentHTML("beforeEnd", anotherHTMLStr)这样的方法来插入HTML,这个方法经过测试,比较稳定。利用limit再加上insertAdjacentHTML,会使得插入的HTML代码速度更稳定,而在Mozilla中,则要利用range的技巧来达到此目的,如下:
if (browser.isMozilla) {
 HTMLElement.prototype.insertAdjacentHTML = function (sWhere, sHTML) {
 var df; var r = this.ownerDocument.createRange();
 switch (String(sWhere).toLowerCase()) {
 case "beforebegin":
 r.setStartBefore(this);
 df = r.createContextualFragment(sHTML);
 this.parentNode.insertBefore(df, this);
 break;
 case "afterbegin":
 r.selectNodeContents(this);
 r.collapse(true);
 df = r.createContextualFragment(sHTML);
 this.insertBefore(df, this.firstChild);
 break;
 case "beforeend":
 r.selectNodeContents(this);
 r.collapse(false);
 df = r.createContextualFragment(sHTML);
 this.appendChild(df);
 break;
 case "afterend":
 r.setStartAfter(this);
 df = r.createContextualFragment(sHTML);
 this.parentNode.insertBefore(df, this.nextSibling);
 break;
 }
 };
}
后记:效率问题没有一个完整的解决方法,只有实践中根据需要而定。因此,上面的方法仅供您参考,如果你也有一些好的方法,可以在评论中写下您的经验,以便交流。
Javascript 相关文章推荐
javascript中全局对象的parseInt()方法使用介绍
Dec 19 Javascript
javascript制作坦克大战全纪录(2)
Nov 27 Javascript
JS中使用apply、bind实现为函数或者类传入动态个数的参数
Apr 26 Javascript
javascript动画系列之模拟滚动条
Dec 13 Javascript
JS实现动态修改table及合并单元格的方法示例
Feb 20 Javascript
Vue.js学习记录之在元素与template中使用v-if指令实例
Jun 27 Javascript
深入理解Node module模块
Mar 26 Javascript
React Router v4 入坑指南(小结)
Apr 08 Javascript
vue百度地图 + 定位的详解
May 13 Javascript
js实现坦克移动小游戏
Oct 28 Javascript
JS+CSS实现3D切割轮播图
Mar 21 Javascript
JavaScript进阶(一)变量声明提升实例分析
May 09 Javascript
你所要知道JS(DHTML)中的一些技巧
Jan 09 #Javascript
sina的lightbox效果。
Jan 09 #Javascript
JS中简单的实现像C#中using功能(有源码下载)
Jan 09 #Javascript
在修改准备发的批量美化select+可修改select时,在非IE下发现了几个问题
Jan 09 #Javascript
兼容Mozilla必须知道的知识。
Jan 09 #Javascript
尽可能写&quot;友好&quot;的&quot;Javascript&quot;代码
Jan 09 #Javascript
添加到收藏夹代码(兼容几乎所有的浏览器)
Jan 09 #Javascript
You might like
PHP入门
2006/10/09 PHP
实现dedecms全站URL静态化改造的代码
2007/03/29 PHP
PHP7基于curl实现的上传图片功能
2018/05/11 PHP
PHP设计模式之抽象工厂模式实例分析
2019/03/25 PHP
JavaScript写的一个自定义弹出式对话框代码
2010/01/17 Javascript
原生Js与jquery的多组处理, 仅展开一个区块的折叠效果
2011/01/09 Javascript
jQuery boxy弹出层插件中文演示及使用讲解
2011/02/24 Javascript
各浏览器对link标签onload/onreadystatechange事件支持的差异分析
2011/04/27 Javascript
如何创建一个JavaScript弹出DIV窗口层的效果
2013/09/25 Javascript
js实现的折叠导航示例
2013/11/29 Javascript
开源的javascript项目Kissy介绍
2014/11/28 Javascript
Extjs实现下拉菜单效果
2016/04/01 Javascript
Jquery ui datepicker设置日期范围,如只能隔3天【实现代码】
2016/05/04 Javascript
js弹出窗口返回值的简单实例
2016/05/28 Javascript
jquery,js简单实现类似Angular.js双向绑定
2017/01/13 Javascript
详解探索 vuex 2.0 以及使用 vuejs 2.0 + vuex 2.0 构建记事本应用
2017/06/16 Javascript
React Native仿美团下拉菜单的实例代码
2017/08/08 Javascript
使用webpack打包koa2 框架app
2018/02/02 Javascript
详解Vue源码学习之callHook钩子函数
2018/07/25 Javascript
在vue中多次调用同一个定义全局变量的实例
2018/09/25 Javascript
JS 设计模式之:单例模式定义与实现方法浅析
2020/05/06 Javascript
Vue+Element自定义纵向表格表头教程
2020/10/26 Javascript
[02:36]DOTA2英雄基础教程 一击致命幻影刺客
2013/12/06 DOTA
python网页请求urllib2模块简单封装代码
2014/02/07 Python
python3.7实现云之讯、聚合短信平台的短信发送功能
2019/09/26 Python
基于tensorflow指定GPU运行及GPU资源分配的几种方式小结
2020/02/03 Python
Java多线程实现四种方式原理详解
2020/06/02 Python
Python下使用Trackbar实现绘图板
2020/10/27 Python
详解Python+Selenium+ChromeDriver的配置和问题解决
2021/01/19 Python
IE兼容css3圆角的实现代码
2011/07/21 HTML / CSS
图解CSS3制作圆环形进度条的实例教程
2016/05/26 HTML / CSS
销售行政专员岗位职责
2014/06/10 职场文书
班子群众路线教育实践个人对照检查材料思想汇报
2014/09/30 职场文书
优秀共产党员事迹材料
2014/12/18 职场文书
在JavaScript中如何使用宏详解
2021/05/06 Javascript
Java由浅入深通关抽象类与接口(下篇)
2022/04/26 Java/Android