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 相关文章推荐
单击浏览器右上角的X关闭窗口弹出提示的小例子
Jun 12 Javascript
JavaScript原生xmlHttp与jquery的ajax方法json数据格式实例
Dec 04 Javascript
JavaScript焦点事件、鼠标事件和滚轮事件使用详解
Jan 15 Javascript
Javascript小技能总结(推荐)
Jun 02 Javascript
微信小程序 商城开发(ecshop )简单实例
Apr 07 Javascript
详解Vue双向数据绑定原理解析
Sep 11 Javascript
为什么我们要做三份 Webpack 配置文件
Sep 18 Javascript
微信{"errcode":48001,"errmsg":"api unauthorized, hints: [ req_id: 1QoCla0699ns81 ]"}
Oct 12 Javascript
JS中通过url动态获取图片大小的方法小结(两种方法)
Oct 31 Javascript
微信小程序自定义多列选择器使用详解
Jun 21 Javascript
django中使用vue.js的要点总结
Jul 07 Javascript
在vue项目实现一个ctrl+f的搜索功能
Feb 28 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实现的json类实例
2015/07/28 PHP
php opendir()列出目录下所有文件的实例代码
2016/10/02 PHP
PHP数组操作简单案例分析
2016/10/15 PHP
JQuery对class属性的操作实现按钮开关效果
2013/10/11 Javascript
JS onmousemove鼠标移动坐标接龙DIV效果实例
2013/12/16 Javascript
eclipse导入jquery包后报错的解决方法
2014/02/17 Javascript
jQuery中prepend()方法用法实例
2014/12/25 Javascript
JQuery datepicker 用法详解
2015/12/25 Javascript
基于JS代码实现实时显示系统时间
2016/06/16 Javascript
JS正则RegExp.test()使用注意事项(不具有重复性)
2016/12/28 Javascript
JS计算斐波拉切代码实例
2019/09/12 Javascript
vue 实现图片懒加载功能
2020/12/31 Vue.js
python中闭包Closure函数作为返回值的方法示例
2017/12/17 Python
python爬取拉勾网职位数据的方法
2018/01/24 Python
Python实现的括号匹配判断功能示例
2018/08/25 Python
python实现QQ邮箱/163邮箱的邮件发送
2019/01/22 Python
通过pycharm使用git的步骤(图文详解)
2019/06/13 Python
Python Django切换MySQL数据库实例详解
2019/07/16 Python
python爬虫selenium和phantomJs使用方法解析
2019/08/08 Python
Pandas 缺失数据处理的实现
2019/11/04 Python
python图片剪裁代码(图片按四个点坐标剪裁)
2020/03/10 Python
Python SMTP配置参数并发送邮件
2020/06/16 Python
Python通过zookeeper实现分布式服务代码解析
2020/07/22 Python
python多线程semaphore实现线程数控制的示例
2020/08/10 Python
五分钟学会HTML5的WebSocket协议
2019/11/22 HTML / CSS
泰国折扣酒店预订:Hotels2Thailand
2018/03/20 全球购物
生产班组长岗位职责
2014/01/05 职场文书
JAVA程序员自荐书
2014/01/30 职场文书
五好党支部事迹材料
2014/02/06 职场文书
端午节活动策划方案
2014/03/09 职场文书
青年文明号创建承诺
2014/03/31 职场文书
小学生综合素质评语
2014/04/23 职场文书
运动会方阵口号
2014/06/07 职场文书
中层干部考核评语
2015/01/04 职场文书
【DOTA2】高能暴走TK秀!PSG LGD vs ASTER - DPC 2022 WINTER TOUR CN
2022/04/02 DOTA
Redis如何实现验证码发送 以及限制每日发送次数
2022/04/18 Redis