JS代码的执行效率往往直接影响了页面的性能,有的时候,实现同样的功能,不同的JS代码往往在效率上相 差很多,有的时候仅仅是由于我们的书写习惯导致的,当然在高级点的浏览器中,它们大多都已经帮我们优化了,但是在中国,万恶的IE6仍然大量的存在,我们 不得不去考虑它。对于JS代码的优化,实际上有很多的情况,有些影响是比较小的,而有些是比较严重的,本文中,我把几个我认为影响比较严重的情况列出来, 供大家参考。

  1、字符串的拼接

  字符串的拼接在我们开发中会经常遇到,所以我把其放在首位,我们往往习惯的直接用+=的方式来拼接字符串,其实这种拼接的方式效率非常的低,我们可以用一种巧妙的方法来实现字符串的拼接,那就是利用数组的join方法。

<div class="one" id="one"></div>
<input type="button" value="效率低" onclick="func1()" />
<input type="button" value="效率高" onclick="func2()" />

//效率低的
function func1(){
var start = new Date().getTime();
var template = "";
for(var i = 0; i < 10000; i++){
template += "<input type='button' value='a'>";
}
var end = new Date().getTime();
document.getElementById("one").innerHTML = template;
alert("用时:" + (end - start) + "毫秒");
}
//效率高的
function func2(){
var start = new Date().getTime();
var array = [];
for(var i = 0; i < 10000; i++){
array[i] = "<input type='button' value='a'>";
}
var end = new Date().getTime();
document.getElementById("one").innerHTML = array.join("");
alert("用时:" + (end - start) + "毫秒");
}

  我们看看其在不同浏览器下执行的情况

  我们会发现,在IE6下其差别是相当明显的,其实这种情况在IE的高版本中体现的也非常明显,但是在Firefox下却没有多大的区别,相反第二种的
相对效率还要低点,不过只是差别2ms左右,而Chrome也和Firefox类似。另外在这里顺便说明一下,在我们给数组添加元素的时候,很多人喜欢用
数组的原生的方法push,其实直接用arr[i]或者arr[arr.length]的方式要快一点,大概在10000次循环的情况IE浏览器下会有十
几毫秒的差别。

  2、for循环

  for循环是我们经常会遇到的情况,我们先看看下面例子:

<input type="button" value="效率低" onclick="func1()" />
<input type="button" value="效率高" onclick="func2()" />
var arr = [];
for(var i = 0; i < 10000; i++){
arr[i] = "<div>" + i + "</div>";
}
document.body.innerHTML += arr.join("");

//效率低的
function func1(){
var divs = document.getElementsByTagName("div");
var start = new Date().getTime();
for(var i = 0; i < divs.length; i++){
//"效率低"
}
var end = new Date().getTime();
alert("用时:" + (end - start) + "毫秒");
}
//效率高的
function func2(){
var divs = document.getElementsByTagName("div");
var start = new Date().getTime();
for(var i = 0, len = divs.length; i < len; i++){
//"效率高"
}
var end = new Date().getTime();
alert("用时:" + (end - start) + "毫秒");
}

  由上表可以看出,在IE6.0下,其差别是非常明显,而在Firefox和Chrome下几乎没有差别,之所以在IE6.0下会有这种情况,主要是因
为for循环在执行中,第一种情况会每次都计算一下长度,而第二种情况却是在开始的时候计算长度,并把其保存到一个变量中,所以其执行效率要高点,所以在
我们使用for循环的时候,特别是需要计算长度的情况,我们应该开始将其保存到一个变量中。但是并不是只要是取长度都会出现如此明显的差别,如果我们仅仅
是操作一个数组,取得的是一个数组的长度,那么其实两种方式的写法都差不多,我们看下面的例子:

<input type="button" value="效率低" onclick="func1()" />
<input type="button" value="效率高" onclick="func2()" />
var arr2 = [];
for(var i = 0; i < 10000; i++){
arr2[i] = "<div>" + i + "</div>";
}
//效率低的
function func1(){
var start = new Date().getTime();
for(var i = 0; i < arr2.length; i++){
//"效率低"
}
var end = new Date().getTime();
alert("用时:" + (end - start) + "毫秒");
}
//效率高的
function func2(){
var start = new Date().getTime();
for(var i = 0, len = arr2.length; i < len; i++){
//"效率高"
}
var end = new Date().getTime();
alert("用时:" + (end - start) + "毫秒");
}   

  从上表可以看出,如果仅仅是一个数组的话,我们看到其实两种写法都是差不多的,其实如果我们把循环再上调到100000次的话,也仅仅是差别几毫秒而
已,所以在数组的情况下,我认为都是一样的。对于for循环的优化,也有人提出很多点,有人认为用-=1,或者从大到小的方式循环等等,我认为是完全没有
必要的,这些优化往往实际情况下根本没有表现出来,换句话说只是计算机级别的微小的变化,但是给我们带来的却是代码的可读性大大的降低,所以实在是得不偿
失。

  3、减少页面的重绘

  减少页面重绘虽然本质不是JS本身的优化,但是其往往是由JS引起的,而重绘的情况往往是严重影响页面性能的,所以完全有必要拿出来,我们看下面例子:

<div id="demo"></div>
<input type="button" value="效率低" onclick="func1()" />
<input type="button" value="效率高" onclick="func2()" />
var str =
"<div>这是一个测试字符串</div><div>这是一个测试字符串<
/div><div>这是一个测试字符串</div><div>这是一个测试字符串<
/div><div>这是一个测试字符串</div><div>这是一个测试字符串<
/div><div>这是一个测试字符串</div><div>这是一个测试字符串<
/div><div>这是一个测试字符串</div><div>这是一个测试字符串<
/div><div>这是一个测试字符串</div><div>这是一个测试字符串<
/div><div>这是一个测试字符串</div>";
//效率低的
function func1(){
var obj = document.getElementById("demo");
var start = new Date().getTime();
for(var i = 0; i < 100; i++){
obj.innerHTML += str + i;
}
var end = new Date().getTime();
alert("用时 " + (end - start) + " 毫秒");
}
//效率高的
function func2(){
var obj = document.getElementById("demo");
var start = new Date().getTime();
var arr = [];
for(var i = 0; i < 100; i++){
arr[i] = str + i;
}
obj.innerHTML = arr.join("");
var end = new Date().getTime();
alert("用时 " + (end - start) + " 毫秒");
}

  在例子中,我只是用了100次的循环,因为如果用10000次循环的话,浏览器基本上就卡住不动了,但是即使是100次的循环,我们看看下面的执行结果。

  可以看到的是,这简直是一个惊人的结果,仅仅100次的循环,不管是在什么浏览器下,都出现了如此之大的差别,另外我们还发现,在这里,IE6的执行
效率居然比起Firefox还要好很多,可见Firefox在页面重绘这方面并没有做一些的优化。这里还要注意的是,一般影响页面重绘的不仅仅是
innerHTML,如果改变元素的样式,位置等情况都会触发页面重绘,所以在平时一定要注意这点。

  4、减少作用域链上的查找次数

  我们知道,js代码在执行的时候,如果需要访问一个变量或者一个函数的时候,它需要遍历当前执行环境的作用域链,而遍历是从这个作用域链的前端一级一
级的向后遍历,直到全局执行环境,所以这里往往会出现一个情况,那就是如果我们需要经常访问全局环境的变量对象的时候,我们每次都必须在当前作用域链上一
级一级的遍历,这显然是比较耗时的,我们看下面的例子:

<div id="demo"></div>
<input id="but1" type="button" onclick="func1()" value="效率低"/>
<input id="but2" type="button" onclick="func2()" value="效率高"/>

function func1(){
var start = new Date().getTime();
for(var i = 0; i < 10000; i++){
var but1 = document.getElementById("but1");
var but2 = document.getElementById("but2");
var inputs = document.getElementsByTagName("input");
var divs = document.getElementsByTagName("div");
var but1 = document.getElementById("but1");
var but2 = document.getElementById("but2");
var inputs = document.getElementsByTagName("input");
var divs = document.getElementsByTagName("div");
var but1 = document.getElementById("but1");
var but2 = document.getElementById("but2");
var inputs = document.getElementsByTagName("input");
var divs = document.getElementsByTagName("div");
var but1 = document.getElementById("but1");
var but2 = document.getElementById("but2");
var inputs = document.getElementsByTagName("input");
var divs = document.getElementsByTagName("div");
var but1 = document.getElementById("but1");
var but2 = document.getElementById("but2");
var inputs = document.getElementsByTagName("input");
var divs = document.getElementsByTagName("div");
var but1 = document.getElementById("but1");
var but2 = document.getElementById("but2");
var inputs = document.getElementsByTagName("input");
var divs = document.getElementsByTagName("div");
}
var end = new Date().getTime();
alert("用时 " + (end - start) + " 毫秒");
}
function func2(){
var start = new Date().getTime();
var doc = document;
for(var i = 0; i < 10000; i++){
var but1 = doc.getElementById("but1");
var but2 = doc.getElementById("but2");
var inputs = doc.getElementsByTagName("input");
var divs = doc.getElementsByTagName("div");
var but1 = doc.getElementById("but1");
var but2 = doc.getElementById("but2");
var inputs = doc.getElementsByTagName("input");
var divs = doc.getElementsByTagName("div");
var but1 = doc.getElementById("but1");
var but2 = doc.getElementById("but2");
var inputs = doc.getElementsByTagName("input");
var divs = doc.getElementsByTagName("div");
var but1 = doc.getElementById("but1");
var but2 = doc.getElementById("but2");
var inputs = doc.getElementsByTagName("input");
var divs = doc.getElementsByTagName("div");
var but1 = doc.getElementById("but1");
var but2 = doc.getElementById("but2");
var inputs = doc.getElementsByTagName("input");
var divs = doc.getElementsByTagName("div");
var but1 = doc.getElementById("but1");
var but2 = doc.getElementById("but2");
var inputs = doc.getElementsByTagName("input");
var divs = doc.getElementsByTagName("div");
}
var end = new Date().getTime();
alert("用时 " + (end - start) + " 毫秒");
}

  上面代码中,第二种情况是先把全局对象的变量放到函数里面先保存下来,然后直接访问这个变量,而第一种情况是每次都遍历作用域链,直到全局环境,我们看到第二种情况实际上只遍历了一次,而第一种情况却是每次都遍历了,所以我们看看其执行结果:

  从上表中可以看出,其在IE6下差别还是非常明显的,而且这种差别在多级作用域链和多个全局变量的情况下还会表现的非常明显。

  5、避免双重解释

  双重解释的情况也是我们经常会碰到的,有的时候我们没怎么考虑到这种情况会影响到效率,双重解释一般在我们使用eval、new Function和setTimeout等情况下会遇到,我们看看下面的例子:

<div id="demo"></div>
<input id="but1" type="button" onclick="func1()" value="效率低"/>
<input id="but2" type="button" onclick="func2()" value="效率高"/>
var sum, num1 = 1, num2 = 2;
function func1(){
var start = new Date().getTime();
for(var i = 0; i < 10000; i++){
var func = new Function("sum+=num1;num1+=num2;num2++;");
func();
}
var end = new Date().getTime();
alert("用时 " + (end - start) + " 毫秒");
}

function func2(){
var start = new Date().getTime();
for(var i = 0; i < 10000; i++){
sum+=num1;
num1+=num2;
num2++;
}
var end = new Date().getTime();
alert("用时 " + (end - start) + " 毫秒");
}

  第一种情况我们是使用了new Function来进行双重解释,而第二种是避免了双重解释,我们看看在不同浏览器下的表现:

  可以看到,在所有的浏览器中,双重解释都是有很大开销的,所以在实际当中要尽量避免双重解释。

  感谢"SeaSunK"对第四点测试报告错误的指正,现在已经修改过来了。至于最后一点提出的func1每次都初始化,没有可比性,所以我给换了
eval,结果发现,在IE6.0下还是有影响,而且在Firefox下,使用eval对效率的影响程度更加厉害,在Firefox下,如果10000次
循环,需要十多秒的时间,所以我把循环都变成了1000次。看代码和报告。

var sum, num1 = 1, num2 = 2;
function func1(){
var start = new Date().getTime();
for(var i = 0; i < 1000; i++){
eval("sum+=num1;num1+=num2;num2++;");
}
var end = new Date().getTime();
alert("用时 " + (end - start) + " 毫秒");
}
function func2(){
var start = new Date().getTime();
for(var i = 0; i < 1000; i++){
sum+=num1;
num1+=num2;
num2++;
}
var end = new Date().getTime();
alert("用时 " + (end - start) + " 毫秒");
}

JS优化代码的更多相关文章

  1. 20个JS优化代码技巧

    原文网址链接为:http://www.jstips.co/ .截取了一部分本人认为比较实用的技巧分享给大家.其中一小部分技巧为JS面向对象的写法,不宜一一列出.关于JS面向对象的写法可参考本人前几篇随 ...

  2. 编写高效的js/jQuery代码 :rocket:

    讨论jQuery和javascript性能的文章并不罕见.然而,本文我计划总结一些速度方面的技巧和我本人的一些建议,来提升你的jQuery和javascript代码.好的代码会带来速度的提升.快速渲染 ...

  3. 关于js优化和css优化

    css优化: 1.css代码的压缩. 2.css文件的合并. 3.不滥用float,因为float在渲染时计算量比较大,所以尽量减少使用float. 4.避免在html标签中写style属性. js优 ...

  4. js优化原则

    首先,与其他语言不同,JS的效率很大程度是取决于JS engine的效率.除了引擎实现的优劣外,引擎自己也会为一些特殊的代码模式采取一些优化的策略.例如FF.Opera和Safari的JS引擎,都对字 ...

  5. 从字符串拼接看JS优化原则

    来自知乎的问题:JavaScript 怎样高效拼接字符串? 请把以下用于连接字符串的JavaScript代码修改为更高效的方式: var htmlString ='< div class=”co ...

  6. 前端js优化方案(连续更新)

    最近在读<高性能javascript>,在这里记录一下读后的一些感受,顺便加上自己的一些理解,如果有兴趣的话可以关注的我的博客http://www.bloggeng.com/,我会不定期发 ...

  7. Webpack 4教程:为什么要优化代码

    转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者.原文出处:https://wanago.io/2018/07/30/webpack-4-course-part ...

  8. js优化 前端小白适用

    注意啦,前端初学者适合看的js优化,当你看我的优化认为太low,那么恭喜,你已经脱离初学者了. 首先这边我觉得分享的还是以js为主,前端性能优化,我认为最重要的还是js,因为js是一门解释型的语言,相 ...

  9. js优化总结

    避免全局查找 在一个函数中会用到全局对象存储为局部变量来减少全局查找,因为访问局部变量的速度要比访问全局变量的速度更快些 function search() {    //当我要使用当前页面地址和主机 ...

随机推荐

  1. reMarkable安装教程

    PS :每次都下一遍安装包挺无奈的...... 系统版本 :Ubuntu 16.04 安装包 :remarkable_1.87_all.deb 链接 Here!-> reMarkable 安装步 ...

  2. ThinkPHP3.1.3分表状态时候的自动验证的代码BUG

    问题描述 ThinkPHP3.1.3 当使用TP的分库分表后 有些地方需要使用Model自动验证create,当验证唯一性unique会出现BUG, 具体描述 因为自动验证检测唯一性会使用隐式的使用f ...

  3. Django入门--模型系统(二):常用查询及表关系的实现

    1.常用查询 模型类上的管理器: ** 模型类.objects ** (1)常用一般查询 rs = Student.objects.all() # 查询所有记录,返回Queryset print(rs ...

  4. C# XML 反序列化解析

    自己用.记录一下! 用于配置文件的解析,可以用来设置配置.不用修改程序里参数. 用微软的XML 解析器来解析的. 1. Xml文件 文件名称:TestConfig.xml <?xml versi ...

  5. python 在爬虫中timeout设置超时有什么作用

    是为了防止url不可访问,或者响应速度太慢而造成的时间浪费. 比如,你要爬取1000个网站,如果有100个需要30s才能返回数据,你等待他们返回的话就需要3000s了,如果你设置10s超时,那么就能知 ...

  6. telnet允许root用户登录

    默认情况下,linux不允许root用户以telnet方式登录linux主机,若要允许root用户登录,可采取以下3种方法之一:    1.修改login文件 redhat中对于远程登录的限制体现在/ ...

  7. C#中的IEnumerable<T>知识点

    1.扩展IEnumerable<T>的方法 使继承了IEnumeralbe<T>的接口有了MyS方法 static class MySum {                  ...

  8. [using_microsoft_infopath_2010]Chapter12 管理监视InfoPath表单服务

    本章概要: 1.在SharePoint中心控制台管理InfoPath设置 2.分析监视浏览器表单开考虑潜在性能问题 3.最小化回发数据

  9. mycat 连续分片 -&gt; 自己定义数字范围分片

    1,自己定义数字范围分片 自己定义数字范围分片,提前规划好分片字段某个范围属于哪个分片,比方说将第一个500W的数据分片在第一个节点上面.第二个500W的数据分片在第二个节点上,依次类推 2,加入配置 ...

  10. C# 跨线程调用form控件技巧及byte[]与string型相互转换

    跨线程调用form控件技巧 private delegate void MethodSocket(object obj);//使用托管 ss = "OK"; this.BeginI ...