本文的一些注意的是我之前看书籍总结的,咱们通常人写项目时,对咱们的影响并非很大,有时彻底能够忽略,可是咱们知道这些总不是什么坏处。javascript
js这个大众语言我想,不少人多知道,它入门和简单,但是想要深刻了解仍是要有必定的水平、 的,一样的效果虽然均可以写出来,但仍是性能和可维护性却有很大差异。下来咱们就来总结一下书写高质量js代码的一些注意点。css
代码维护是高成本的,若是咱们在开发代码时,不注重代码的规范,可读性和可维护性,那么未来带给咱们的将是更大的开支。若是说你是给公司干活,本身写完就不用管了,这样的思想很危险。不但对他人读取你代码时带来困扰,同时也是限制本身发展的一个障碍。代码终究是要给人去阅读的。咱们整个团队在书写代码时应该劲量作到:java
管理浏览器中的脚本 JavaScript 代码是个棘手的问题,由于代码执行过程会阻塞浏览器的其余进程,好比用户界面绘制,每次遇到<script>
标签,页面都必须停下来等待代码下载(若是是外链文件)并执行,而后继续处理其余部分,尽管如此,仍是有几种方法能减小javascript
对性能的影响。web
<script>
标签放到页面底部,这确保在脚本执行前页面已加载完成了渲染。<script>
标签越少,加载也就也快,响应也更迅速。不管外链文件仍是内嵌脚本都是如此<script>
标签的defer属性(H5提供一个新属性async)defer和async的相同点是采用并行下载,在下载过程当中不会产生阻塞。区别在于执行时机,async是加载完成后自动执行,而defer须要等待页面完成后执行。算法
<script type="text/javascript" defer></script> <script type="text/javascript" async></script>
<script>
元素来下载并执行代码<script>
元素不会阻塞页面的其余进程,这样咱们能够将动态建立的<script>
放到页面的 <head>
区域。function(url){ var script = document.creatElement('script'); script.type = "text/javascript"; script.src = url; document.getElementsByTagName('head')[0].appendChild(script); }
咱们何时知道脚本已经加载完成呢?Firefox,Opera,Chrome和safari3为咱们提供了一个onload
事件来监听,而IE 为咱们提供了onreadystatechange
事件并根据readyState属性来进行判断
。数组
经过上面的方法,咱们能够极大提升那些须要使用大量的JavaScript
的 web应用的实际性能浏览器
咱们都知道,JavaScript经过函数管理做用域。在函数内部声明的变量只在这个函数内部,函数外面不可用。另外一方面,全局变量就是在任何函数外面声明的或是未声明直接简单使用的。咱们应该尽可能的减小全局变量,这样避免全局变量过多而形成变量命名冲突,同时又占用内存。缓存
声明变量是咱们尽可能用var
去声明数据结构
function fun(){ a = 1; // 这样是不推荐的,由于a是隐式的全局变量 var b = 2; // 这样是推荐的 var c = d = 5 // 这样也是不推荐的,由于d是隐式的全局变量 }
减小全局变量咱们还可使用当即执行函数,下来咱们也会有章节去详细的讲解app
(function(){ var a = 3; var b = 4; })()
另外咱们应该知道变量提高原则,这个在后面的章节中咱们还会详细的讲解咱们在写一些变量时,能够这样去写。
function(){ var a, b, c; a = 1; b = 2; c = 3; }
咱们把经常使用的变量写到最上面,能够进行注释,这样更有利于维护咱们的代码,同时防止变量在定义以前使用的逻辑错误。
脚本进行DOM的操做的代价是很昂贵的。它是富Web应用中最多见的性能瓶颈。浏览器中一般会把DOM 和 JavaScript(ECMAScript) 独立实现。咱们每一次用js去操做DOM都会产生性能消耗,因此咱们尽量小的去处理DOM,这也是如今MVVM和MVC框架流行的一部分缘由。咱们在处理DOM时尽量这样作。
1.最小化DOM访问次数,尽量在JavaScript端处理
var ul = document.getElementById("ul"); var a = ""; for(var i=0;i<10;i++){ a += "<li>i</li>"; } ul.innerHTML = a;
将要添加的标签存储在变量a中,一次性加入ul中,这样只访问一次dom,下降了性能消耗。
2.若是须要屡次访问某个DOM节点,请使用局部变量存储它的引用
var doc = document; // 存储document doc.getElementById("div");
3.当心处理HTML集合,由于它实时连系着底层文档,把集合的长度缓存到一个变量中,并在迭代中使用它。若是须要常常操做集合,建议把它拷贝到一个数组中。
var divList = document.getElementsByTagName("div"); for(var i = 0,len = divList.length; i < len; i++){ }
这里咱们将divList
的长度去存储在变量 len中,而不像下面这样每次循环都要读取一遍长度。
// 避免使用的例子 var divList = document.getElementsByTagName("div"); for(var i = 0; i < divList.length; i++){ }
4.若是可能的话,使用速度更快的API,好比querySelectorAll()
和 firstElementChild
5.要留意重绘和重排;批量修改样式时,'离线'操做DOM树,使用缓存、并减小访问布局信息的次数
浏览器下载完页面中的全部组件以后会解析并生成两个内部数据结构
DOM树: 表示页面结构
渲染树: 表示DOM节点如何显示
当DOM的变化影响了元素的几何属性时(宽高)—— 好比改变框宽度或给段落增长文字,致使行数增长,浏览器须要从新计算元素的几何属性,一样其余元素的几何属性和位置也会所以受到影响,浏览器会是渲染树中受到影响的部分失效,并从新构造渲染树。这一过程称为 “重排(reflow)”。完成重排后,浏览器会从新绘制影响的部分到屏幕中,该过程称为 “重绘”。
那么咱们该怎么减小重排和重绘
//这种写法不推荐 var el = document.getElementById("div"); el.style.width = '100px'; el.style.height = '100px'; el.style.padding = '10px'; //这种写法推荐 var el = document.getElementById("div"); el.style.cssText = "width:100px;height:100px;padding:5px;";
下边的方法很明显只进行了一次重排,而上边的重排了三次。使用cssText
时会覆盖前边的style样式,咱们能够这样作
el.style.cssText += "width:100px;height:100px;padding:5px;";
另外咱们还能够将改变的样式写在css样式表中,经过修改class来改变其样式。
var el = document.getElementById("div"); el.className = "active";
脱离文档修改DOM的步骤就是
使元素脱离文档流
对其应用多重改变
把元素带回文档中
这里我有三种方法:
(1) 第一种:隐藏元素,应用修改,从新显示
var el = document.getElementById("div"); el.style.display = "none"; el.style.width = '100px'; el.style.height = '100px'; el.style.padding = '10px'; el.style.display = "block";
(2) 第二种:使用文档片断在当前DOM以外构建一个子树,在把它拷贝回文档
var el = document.getElementById("ul"); var fragment = document.createDocumentFragment(); for(var i = 0; i < 50000; i++){ fragment.appendChild(document.createElement("li")); } el.appenChild(fragment);
推荐使用这种方式。
(3) 第三种:将原始元素拷贝到一个脱离文档的节点中,修改副本,完成后在提货原始元素
var el = document.getElementById("div"); var cloneDiv = el.choleNode(true); cloneDiv.appendChild = li; el.parentNode.replaceChild(clone,el);
以上脱离文档流修改DOM的方法推荐第二种方法。
因为每次重排都会产生计算消耗,大多数浏览器经过列队化修改并批量执行来优化重排过程。而咱们不知不觉中就使用了一些强制刷新队列并要求计划任务马上执行的方法:
1. offsetTop、offsetLeft、offsetWidth、offsetHeight 2. scrollTop、scrollLeft、scrollWidth、scrollHeight 3. clientTop、clientLeft、clientWidht、clientHeight 4. getComputedStyle() // currentStyle IE中
咱们在使用上面方法时要注意,浏览器为了返回最新值,会刷新队列应用所用变动,咱们应该减小他们的使用,若是使用他们咱们最好缓存布局信息
例如咱们将滚轮滚动到页面顶部:
var scroll = document.body.scrollTop; // 这里直接缓存scrollTop var set = setInterval(function(){ scroll--; // 这里不使用window.scrollTop-- document.body.scrollTop = scroll; if(scroll < 0) { clearInterval(set); } },100)
6.动画中使用绝对定位。
对于用展开/折叠的效果,咱们使用绝对定位,将其脱离文档流,会是重绘更少些。
7.使用事件委托来减小事件处理器的数量。
若是你还不知道事件委托事什么,请访问:
http://blog.csdn.net/webxiaoma/article/details/53501616
这里咱们讨论的是循环和判断,咱们直接写推荐的书写方法
1.循环体
循环包括 for
循环、while
循环、do-while
循环、for-in
循环。
其中for-in
循环的性能明显比其余性能差些,另外ES6对于属性循环有出了for-of
循环,比起for-in
循环性能要好一些。
咱们前面也说了,循环时,咱们最好存储判断的长度,另外递减循环要比递加循环速度至关要快。
2.判断
判断有:if
和 switch
;
当咱们作判断时,最好是吧最有可能出现的放到前面,另外if-else-if
不少的话,推荐使用switch
去判断,这样更有利于减小性能的消耗。有时候咱们选择嵌套if也不使用不少if-else-if
连用的方法以下:
// 推荐 if(){ if(){ if(){ } } } // 尽可能少用 if(){ } else if(){ } else if(){ } else if(){ } else if(){ } else if(){ }
对象的注意点是:
1.尽可能不扩展内置原型(如给Object.prototype添加本身的方法),除非你肯定不会对你的团队形成影响
2.访问的做用域和对象越深,越消耗性能,咱们 尽可能减小,不过这并非硬性的要求,咱们尽可能减小那些没必要要的深刻访问。
var a = 0; if(a === false){ //不执行 } if(a == false){ //执行了 }
2.尽可能少的使用eval()
3.项目发布时的代码压缩,js文件整合,图片整合等等优化。
4.整个团队的代码书写风格,要肯定。
文章基本就写到这里,项目书写的注意点不仅仅只有这些,其实对代码的优化还有不少,还有你的经验。不断积累必定会写成很优雅的代码。
参考文献:《高性能JavaScript》