前端工程优化:javascript的优化小结
我觉得优化javascript是一门高深的学问,在这里也只能站在前人的肩膀上,说一些我浅显的认识,更希望的是抛钻引玉,如有不对,敬请斧正。
首先,要认识到是,优化js的关键之处在于,优化它的运行速度,以此为切入点。
javascript的优化原则是:二八原则
满足考量大多数情况,而遇到极端情况,有能力则兼顾之,学会放弃,适当取舍;
原因是,影响用户的体验很重要的因素之一响应时间
- 0.1s: 用户觉得很流畅
- 1.0s: 用户的操作可能偶尔受到影响,并且用户已经能感觉到有些不流畅
- 10s : 对用户的影响比较严重,需要相应的进度提示。用户也会有一些沮丧 (//我觉得10s太宽泛了,通常而言2s以上就受不了了)
当然js优化只是提升响应时间需要改善的方面的众多之一,前端优化知识何其之深,只有深入了解,才会惊讶于前端所需要掌握的知识竟是如此之多,当然无形之中也会给人压力||动力。扯远了,但是还是想力荐两篇关于前端优化的blog:前端工程打开速度优化的循序渐进总结 和 web前端优化最佳实践及工具。
继续正题,ok,那么知道了目标是提升响应时间,加快运行速度,那么具体有哪些可行的方案呢:
- 管理作用域
- 操作数据
- 流控制
- Reflow
- DOM操作
- 长时间运行的脚本处理
管理作用域
举个板栗:
var foo = 1;
function test(){
//对变量foo进行一系列操作
} function test2(){
var foo = 1;
//对变量foo进行一系列操作
}
也就是说,局部变量存在于活动对象中,解析器只需查找作用域中的单个对象。
在JavaScript中,我们应该尽可能的用局部变量来代替全局变量,这句话所有人都知道,可是这句话是谁先说的?为什么要这么做?有什么根据么?不这么做,对性能到底能带来多大的损失?以下是我摘自《JavaScript Variable Performance》的一段:
在如何提高JavaScript性能这个问题上,大家最常听到的建议应该就是尽量使用局部变量(local variables)来代替全局变量(global variables)。在我从事Web开发工作的九年时间里,这条建议始终萦绕在我的耳边,并且从来没有质疑过,而这条建议的基础,则来自于 JavaScript处理作用域(scoping)和标识符解析(identifier resolution)的方法。 首先我们要明确,函数在JavaScript中具体表现为对象,创建一个函数的过程,其实也就是创建一个对象的过程。每个函数对象都有一个叫做 [[Scope]]的内部属性,这个内部属性包含创建函数时的作用域信息。实际上,[[Scope]]属性对应的是一个对象(Variable Objects)列表,列表中的对象是可以从函数内部访问的。比如说我们建立一个全局函数A,那么A的[[Scope]]内部属性中只包含一个全局对象(Global Object),而如果我们在A中创建一个新的函数B,那么B的[[Scope]]属性中就包含两个对象,函数A的Activation Object对象在前面,全局对象(Global Object)排在后面。当一个函数被执行的时候,会自动创建一个可以执行的对象(Execution Object),并同时绑定一个作用域链(Scope Chain)。作用域链会通过下面两个步骤来建立,用于进行标识符解析。
- 首先将函数对象[[Scope]]内部属性中的对象,按顺序复制到作用域链中。
- 其次,在函数执行时,会创建一个新的Activation Object对象,这个对象中包含了this、参数(arguments)、局部变量(包括命名的参数)的定义,这个Activation Object对象会被置于作用域链的最前面。
在执行JavaScript代码的过程中,当遇到一个标识符,就会根据标识符的名称,在执行上下文(Execution Context)的作用域链中进行搜索。从作用域链的第一个对象(该函数的Activation Object对象)开始,如果没有找到,就搜索作用域链中的下一个对象,如此往复,直到找到了标识符的定义。如果在搜索完作用域中的最后一个对象,也就是全局对象(Global Object)以后也没有找到,则会抛出一个错误,提示用户该变量未定义(undefined)。这是在ECMA-262标准中描述的函数执行模型和标识符解析(Identifier Resolution)的过程,事实证明,大部分的JavaScript引擎确实也是这样实现的。需要注意的是,ECMA-262并没有强制要求采用这种结构,只是对这部分功能加以描述而已。 了解标识符解析(Identifier Resolution)的过程以后,我们就能明白为什么局部变量的解析速度要比其他作用域的变量快,主要是由于搜索过程被大幅缩短了。
也就是:当标识符解析的过程需要进行深度搜索时,会伴随性能损失,而且性能损失的程度会随着标识符深度的增加而递增。
数据操作
1. 使用局部变量,它是最快的
obj.name比obj.xxx.name访问更快,访问属性的速度,与其在对象中的深度有关。“ . ”操作的次数直接影响着访问对象属性的耗时。
2. 缓存频繁使用的对象、数组及相关的属性值
function process(data){
var count = data.count;
if (count > 0){
for(var i = 0; i < count ; i++){
processData(data.item[i]);
}
}
}
3. 不直接操作NodeList,将其转换成静态数组后再使用
方法: Array.prototype.slice.call() => 标准浏览器
逐个拷贝到一个新数组中 => For IE
需要注意的是,遍历NodeList时,不做对当前NodeList相关结构有影响的DOM操作,并且如之前所提到的,要缓存一些频繁使用到的属性值,以免发生不必要的悲剧。板栗:
var divs = document.getElementsByTagName('DIV'); //假定页面中有div,所以divs.length是大于0的
for (var idx = 0; idx < divs.length; idx++){
document.body.appendChild(
//杯具悄然而置
document.createElement('DIV')
);
console.info(divs.length);
}
上面的代码最后运行会报错,原因通过不断地往document.body下插入div 节点,for循环的终止条件( div.length也随之改变)失效,陷入死循环。也就是说通过getElementsByTagName()获取得到的是一个Live NodeList的引用,任何对其相关的DOM操作都会立即反应在这个NodeList上面。
Dom操作
1. 增删查改
- 尽量使用DocumentFragment
- 处理节点时可以使用cloneNode()复制一份
- 若要对DOM进行直接修改,请先将其display:none;
2. 指明操作DOM的context
context.getElementsByTagName()
3. 拆分方法,一个方法解决一件事
拆分功能,让一个方法只做一件事,通过不断地调用方法来实现复杂功能,但是,这些简单方法要避免相互交叉调用。
Be Lazy(使脚本尽可能少地运行,或者不运行。)
- 短路表达式应用:如 a && b || c
- 基于事件去写相应的处理方法
- 惰性函数
流控制
if(...){
}
elseif(...){
}
elseif(...){
}
elseif(...){
}
elseif(...){
}
elseif(...){
}
else{
}
原则:
- 在if语句中,将经常会发生的条件,放在靠上的位置
- if的条件为连续的区间时,可以使用二分法的方式来拆分
- 较多离散值的判断,可以使用switch来替代
- 使用数组查询的方式
- 要注意隐式的类型转换
- 小心递归
var foo = 0; if(foo == false){ //隐式转换
...
}
function recurse(){
recurse();
}
recurse(); //又是一个悲剧,会报错,无限递归了
Reflow
何为reflow,即是:在CSS规范中有一个渲染对象的概念,通常用一个盒子(box, rectangle)来表示。mozilla通过一个叫frame的对象对盒子进行操作。frame主要的动作有三个:
- 构造frame, 以建立对象树(DOM树)
- reflow, 以确定对象位置,或者是调用mozilla的Layout(这里是指源码的实现)
- 绘制,以便对象能显示在屏幕上
总的来说,reflow就是载入内容树(在HTML中就是DOM树)和创建或更新frame结构的响应的一种过程。
那么造成reflow的原因有:
- 操作DOM树
- 与布局有关的样式改变
- 改变className
- 窗口大小调整
- 字休大小
所以若要要提高页面性能,其实就是避免reflow的开销,但是造成reflow的原因有时候是为了完成交互效果而不可避免的,所以不能说完全避免,只能尽最大限度的去减少,这就如我开头而言的二八原则。
以下是一些简单的指导方针可以帮助你页面上的回流(reflow)减到最小。
- 减少不必要的DOM深度。因为无论你改变DOM节点树上任何一个层级都会影响节点树的每个层级——从根结点一直到修改的子节点。不必要的节点深度将导致执行回流时花费更多的时间。
- 精简css,去除没有用处的css
- 如果你想让复杂的表现发生改变,例如动画效果,那么请在这个流动线之外实现它。使用position-absolute或position-fixed来实现它。
- 避免不必要的复杂的css选择符,尤其是使用子选择器,或消耗更多的CPU去做选择器匹配。
转载注明出处:http://www.cnblogs.com/coco1s/p/3946435.html
前端工程优化:javascript的优化小结的更多相关文章
- 前端html、Javascript、CSS技术小结
简单地总结了一下前端用过的html.javascript.css技术,算是清点一下,做个大略的小结,为进一步的学习给个纲领. 一.HTML 由于HTML5的兴起,简单地判断一个网页是否是html5网页 ...
- JavaScript内存优化
JavaScript内存优化 相对C/C++ 而言,我们所用的JavaScript 在内存这一方面的处理已经让我们在开发中更注重业务逻辑的编写.但是随着业务的不断复杂化,单页面应用.移动HTML5 应 ...
- Web前端性能优化之图片优化
我自己的Blog:http://blog.cabbit.me/web-image-optimization/ HTTP Archieve有个统计,图片内容已经占到了互联网内容总量的62%,也就是说超过 ...
- 优化javaScript代码,提高执行效率
今天看完书,总结了一下可以如何优化 JavaScript . 1.合并js文件 为优化性能,可以把多个js文件(css文件也可以)合并成极少数大文件.跟十个5k的js文件相比,合并成一个50k的文件更 ...
- web前端除了关注代码功能实现,还应具备web性能优化以及SEO优化的常识
web前端除了关注代码功能实现,还应具备web性能优化以及SEO优化的常识 ——不会WPO.SEO的前端工程师不是好码农 作为一名web前端工程师,除了要实现上级的要求,满足其所需要的功能,还要在平时 ...
- 前端Yslow的23个优化原则
前端Yslow的23个优化原则 最常遇见的前端优化问题. Yslow是雅虎开发的基于网页性能分析浏览器插件,可以检测出网页的具体性能值,并且有著名的Yslow 23条优化规则,这23条,就够我们玩的了 ...
- JavaScript性能优化
如今主流浏览器都在比拼JavaScript引擎的执行速度,但最终都会达到一个理论极限,即无限接近编译后程序执行速度. 这种情况下决定程序速度的另一个重要因素就是代码本身. 在这里我们会分门别类的介绍J ...
- javascript性能优化:创建javascript无阻塞脚本
javaScript 在浏览器中的运行性能,在web2.0时代显得尤为重要,成千上万行javaScript代码无疑会成为性能杀手, 在较低版本的浏览器执行JavaScript代码的时候,由于浏览器只使 ...
- javascript性能优化-repaint和reflow
repaint(重绘) ,repaint发生更改时,元素的外观被改变,且在没有改变布局的情况下发生,如改变outline,visibility,background color,不会影响到dom结构渲 ...
随机推荐
- C#_取随机字符
1.多位数字字母组成,每位取值0-9A-Z /// <summary> /// 获取下一个顺序码根据上一个(数字字母组合) /// </summary> /// <par ...
- Sublime Text 3实用快捷键大全
下面是我通过网上教程和文本资料学习sublime Text3时收集的一些实用功能和常用快捷键,现在分享出来,如果还有其它的好用的功能可以在下面留言,以便互相学习和交流,谢谢!. 选择类 Ctrl+ ...
- webstorm快捷键
webstorm应该是目前最强的js编辑器了,结合sublime text可以很效率的开发项目.今天整理了一些webstorm比较实用的快捷键: Ctrl+/ 或 Ctrl+Shift+/ 注释(// ...
- phpstudy虚拟机配置
PHPStudy是一个常用的PHP本地环境搭建的一个程序包,方便实用.对学习PHP的新手来说, WINDOWS下环境配置是一件很困难的事;对老手来说也是一件烦琐的事.因此无论你是新手还是老手,该程序包 ...
- windows下装多个node版本的方法(gnvm)
安装一个支持windows切换node版本的工具 工作中我们可能需要用到一些工具,但这些工具依赖不同版本的node环境,那我们需要来为的切换node的环境吗, window msi安装的用户需要卸 ...
- 【http代理报文】通过发包实现代理请求网页内容
工作中,我们难免需要通过TCP/IP协议发送报文来直接请求网页内容(比如爬虫工具),有同学问如何通过HTTP代理来请求网页,其实我们只需要把报文稍稍修改下,发送给代理服务器即可实现. 基础不过关的朋友 ...
- (翻译)开始iOS 7中自动布局教程(二)
这篇教程的前半部分被翻译出来很久了,我也是通过这个教程学会的IOS自动布局.但是后半部分(即本篇)一直未有翻译,正好最近跳坑翻译,就寻来这篇教程,进行翻译.前半部分已经转载至本博客,后半部分即本篇.学 ...
- jetty项目中静态文件不能修改问题
修改web.xml 在web.xml中加入如下代码: <servlet> <servlet-name>default</servlet-name> <serv ...
- C语言的傻瓜式随笔(一):嵌套循环-程序结构
循环语句的嵌套 一个循环结构内可以含有另一个循环,称为循环嵌套,又称多重循环.常用的循环嵌套是二重循环,外层循环称为外循环,内层循环称为内循环. ---------不知道哪来的基础概念 这是本宝宝的第 ...
- GIT和SVN之间的区别及基本操作对比
1)GIT是分布式的,SVN不是: 这是GIT和其它非分布式的版本控制系统,例如 SVN,CVS等,最核心的区别.如果你能理解这个概念,那么你就已经上手一半了.需要做一点声明,GIT并不是目前第一个或 ...