JavaScript提高网站性能优化的建议(二)


Posted in Javascript onJuly 24, 2016

在javascript关于提高网站性能的几点建议(一)中,从HTTP请求到页面渲染几个方面对提高网站性能提出了几点建议,本文是学习Steve Sounders的另外一本书《高性能网站建设进阶指南》之后,从JavaScript性能的角度进行总结概括,诸君共勉。

JavaScript性能是实现高性能Web应用程序的关键

——Steve Sounders

1 利用js作用域链

作用域链(scope chain)

当执行一段JavaScript代码(全局代码或函数)时,JavaScript引擎会创建为其创建一个作用域又称为执行上下文(Execution Context),在页面加载后会首先创建一个全局的作用域,然后每执行一个函数,会建立一个对应的作用域,从而形成了一条作用域链。每个作用域都有一条对应的作用域链,链头是全局作用域,链尾是当前函数作用域。

作用域链的作用是用于解析标识符,当函数被创建时(不是执行),会将this、arguments、命名参数和该函数中的所有局部变量添加到该当前作用域中,当JavaScript需要查找变量X的时候(这个过程称为变量解析),它首先会从作用域链中的链尾也就是当前作用域进行查找是否有X属性,如果没有找到就顺着作用域链继续查找,直到查找到链头,也就是全局作用域链,仍未找到该变量的话,就认为这段代码的作用域链上不存在x变量,并抛出一个引用错误(ReferenceError)的异常。

管理好作用域链的深度,是一种只要少量工作就能提高性能的简易方法,我们应避免因无意中增长了作用域链而导致执行速度变得缓慢。

使用局部变量(尽量缩短作用域链)

如果理解了作用域链的概念,那么我们应该清楚JavaScript引擎对变量的解析时间跟作用域链的深度有关,显而易见,局部变量由于处于链尾,存取速度是最快的,因此,一个好的经验是:任何非局部变量使用超过一次时,请使用局部变量将其存储下来,例如:

function changeDiv(){
document.getELementById('myDiv').className = 'changed';
document.getELementById('myDiv').style.height = 150;
}

这里myDiv这个dom元素被引用了两次,为了更快的引用,我们应该用一个局部变量将其存储下来,这样做的好处不仅缩短了作用域链,而且避免了DOM元素的重复查询:

function changeDiv(){
var myDivStyle = document.getElementById('myDiv').style;
myDiv.className = 300;
myDiv.style.height = 150;
}

避免使用with(不要增长作用域链)

一般在代码执行过程中,函数的作用域链是固定的,然而with可以临时增长函数的作用域链。with用于将对象属性作为局部变量来显示,使其便于访问,例如:

var user = {
name:'vicfeel',
age:'23'
};
function showUser(){
var local = 0;
with(user){
console.log("姓名" + name);
console.log("年龄" + age);
console.log(local);
}
}
showUser();

这个例子中,通过with在showUser作用域链的链尾中又增加了一个临时作用域,该作用域存储着user对象的所有属性,也就是增长了with这段代码的作用域链,在这段代码中,局部变量像local从链尾的第一个对象变成了第二个,自然减慢了标识符的存取。直到with语句结束,作用域链恢复增长。正因为with的这个缺陷,我们应尽量避免使用with关键字。

2 更合理的流控制

JavaScript与其它编程语言一样,拥有一些流控制语句(循环、条件等),在每个环节上使用恰当的语句能极大的提高脚本的运行速度。

快速条件判断

提到条件判断,首先要避免的一种使用方式:

if(value == 0){
return result0;
}
else if(value == 1){
return result1;
}
else if(value == 2){
return result2;
}
else if(value == 3){
return result3;
}
else if(value == 4){
return result4;
}
else if(value == 5){
return result5;
}
else if(value == 6){
return result6;
}
else{
return result7;
}

这种使用if进行条件判断的方式存在的主要问题是层次太深,当我要value = 7时,消耗时间要比value = 0长很多,大大损耗了性能,同时可读性很差。

一种更好的方式,利用switch进行判断。

swithc(value){
case 0:
return result0;
case 1:
return result1;
case 2:
return result2;
case 3:
return result3;
case 4:
return result4;
case 5:
return result5;
case 6:
return result6;
default:
return result7;
}

这样不仅提高了可读性,查询时间也要比if更快。但是如果只有一两个条件时,if是比switch更快的

在JavaScript中,条件查询还有另外一种方式,之前的例子是根据值返回不同的值,刚好可以利用数组实现hash表的映射查询。

//定义数组
var results = [result0,result1,result2,result3,result4,result5,result6,result7];
//查询结果
return results[value];

这种数组的方式,在查询范围很大时才更加有效,因为它不必检测上下边界,只需要填入索引值就可以查询了。它的局限性在于条件对应的是单一值,而不是一系列操作。因此要综合实际情况,选择合适的条件判断方式,发挥性能最大化。

快速循环

JavaScript中存在4种循环方式for循环、do-while循环、while循环和for-in循环。下面是一个很常用的循环使用方式:

var values = [1,2,3,4,5];
for(var i = 0;i < values.length;i++){
process(values[i]);
}

我们可以看到,这段代码最明显可以优化的地方在于values.length,每次循环i都要和values的长度进行比较,而查询属性要比局部变量更耗时,如果循环次数越大,这种耗时就越明显,因此可以这样优化:

var values = [1,2,3,4,5];
var length = values.length;//局部变量存储数组长度
for(var i = 0;i < length;i++){
process(values[i]);
}

这段代码还可以继续优化,将循环变量递减到0,而不是递加到总长度。

var values = [1,2,3,4,5];
var length = values.length;
for(var i = length;i--;){ //递减到0
process(values[i]);
}

这里将循环结束改造为与0比较,所以每个循环的速度更快了,根据循环的复杂度不同,这种简单改变可以比原来节约大概50%的时间。

Javascript 相关文章推荐
jquery键盘事件使用介绍
Nov 01 Javascript
简单的Jquery遮罩层代码实例
Nov 14 Javascript
js实现select跳转菜单新窗口效果代码分享(超简单)
Aug 21 Javascript
JavaScript+html5 canvas绘制缤纷多彩的三角形效果完整实例
Jan 26 Javascript
浅谈JavaScript中数组的增删改查
Jun 20 Javascript
详解JavaScript中js对象与JSON格式字符串的相互转换
Feb 14 Javascript
Vue父子组件之间的通信实例详解
Sep 28 Javascript
简单两步使用node发送qq邮件的方法
Mar 01 Javascript
vue组件开发之slider组件使用详解
Aug 21 Javascript
vue的$http的get请求要加上params操作
Nov 12 Javascript
给原生html中添加水印遮罩层的实现示例
Apr 02 Javascript
JS中forEach()、map()、every()、some()和filter()的用法
May 11 Javascript
JavaScript学习小结之使用canvas画“哆啦A梦”时钟
Jul 24 #Javascript
省市二级联动小案例讲解
Jul 24 #Javascript
基于jQuery实现多标签页切换的效果(web前端开发)
Jul 24 #Javascript
js简单实现调整网页字体大小的方法
Jul 23 #Javascript
jquery实现ajax加载超时提示的方法
Jul 23 #Javascript
数据结构中的各种排序方法小结(JS实现)
Jul 23 #Javascript
js的各种排序算法实现(总结)
Jul 23 #Javascript
You might like
PHP写杨辉三角实例代码
2011/07/17 PHP
php实现的简单多进程服务器类完整示例
2020/02/01 PHP
TNC vs RR BO3 第一场 2.14
2021/03/10 DOTA
Javascript 错误处理的几种方法
2009/06/13 Javascript
让JavaScript拥有类似Lambda表达式编程能力的方法
2010/09/12 Javascript
常用的jquery模板插件——jQuery Boilerplate介绍
2014/09/23 Javascript
在jQuery中处理XML数据的大致方法
2015/08/14 Javascript
轻量级jQuery插件slideBox实现带底栏轮播(焦点图)代码
2016/03/28 Javascript
jQuery使用getJSON方法获取json数据完整示例
2016/09/13 Javascript
利用Js的console对象,在控制台打印调式信息测试Js的实现
2016/11/26 Javascript
浅谈js在html中的加载执行顺序,多个jquery ready执行顺序
2016/11/26 Javascript
原生js实现吸顶效果
2017/03/13 Javascript
详解vue前后台数据交互vue-resource文档
2017/07/19 Javascript
JS分页的实现(同步与异步)
2017/09/16 Javascript
详解用webpack的CommonsChunkPlugin提取公共代码的3种方式
2017/11/09 Javascript
简单了解微信小程序的目录结构
2019/07/01 Javascript
微信小程序开发技巧汇总
2019/07/15 Javascript
你可能从未使用过的11+个JavaScript特性(小结)
2020/01/08 Javascript
vscode 插件开发 + vue的操作方法
2020/06/05 Javascript
在vue中获取wangeditor的html和text的操作
2020/10/23 Javascript
使用PyInstaller将Python程序文件转换为可执行程序文件
2016/07/08 Python
python 计算数组中每个数字出现多少次--“Bucket”桶的思想
2017/12/19 Python
利用Python如何实现数据驱动的接口自动化测试
2018/05/11 Python
对Python中list的倒序索引和切片实例讲解
2018/11/15 Python
Python提取支付宝和微信支付二维码的示例代码
2019/02/15 Python
python如何实现异步调用函数执行
2019/07/08 Python
Python中的延迟绑定原理详解
2019/10/11 Python
Python with关键字,上下文管理器,@contextmanager文件操作示例
2019/10/17 Python
洛杉矶时尚女装系列:J.ING US
2019/03/17 全球购物
Lookfantastic澳大利亚官网:英国知名美妆购物网站
2021/01/07 全球购物
澳大利亚领先的女性运动服品牌:Lorna Jane
2020/06/19 全球购物
2014年班主任自我评价范文
2014/04/23 职场文书
2014公司党员自我评价范文
2014/09/11 职场文书
爱心助学感谢信
2015/01/21 职场文书
在Python中如何使用yield
2021/06/07 Python
浅谈Web Storage API的使用
2021/06/23 Javascript