关于前端性能优化的讨论一直都不少,包罗的知识也不少,能够说性能优化只有更好,没有最好。前面我写了一篇关于css优化的总结文章,今天再从javascript方面聊一聊。javascript
1.从资源加载方面来讲,浏览器的加载顺序是按源码从上到下加载解析的,遇到link
,script
等资源都会阻塞页面渲染,因此咱们会把script
放在</body>
前面,咱们还能够结合构建工具(webpack,gulp...)压缩js文件,抽离公共js、去掉空格、注释,尽量地让js文件变小,防止脚本阻塞页面渲染。css
2.在写代码的时候咱们还要注意如下问题。前端
(1)减小做用域链上的查找次数。咱们知道,js代码在执行的时候,若是须要访问一个变量或者一个函数的时候,它须要从当前执行环境的做用域链一级一级地向上查找,直到全局做用域。若是咱们须要常常访问全局环境的变量对象的时候,咱们每次都必须在当前做用域链上一级一级的遍历,这显然是比较耗时的。java
function getTitle() { var h1 = document.getElementByTagName("h1"); for(var i = 0, len = h1.length; i < len; i++) { h1[i].innerHTML = document.title + " 测试 " + i; } }
上面这样写就很是耗时,咱们能够优化一下:node
function getTitle() { var doc = document; var h1 = doc.getElementByTagName("h1"); for(var i = 0, len = h1.length; i < len; i++) { h1[i].innerHTML = doc.title + " 测试 " + i; } }
经过建立一个指向document的局部变量,就能够经过限制一次全局查找来改进这个函数的性能。jquery
(2)闭包致使的内存泄露。
闭包能够保证函数内的变量安全,能够读取函数内部的变量,另外一个就是让这些变量的值始终保持在内存中,不会被自动清除。使用场合:设计私有的方法和变量。使用不当就会形成内存占用太高。咱们须要手动销毁内存中的变量。webpack
(3)尽可能少用全局变量,尽可能使用局部变量。全局变量若是不手动销毁,会一直存在,形成全局变量污染,可能很产生一些意想不到的错误,而局部变量运行完成后,就被会被回收;web
(4)使用classname代替大量的内联样式修改。不少时候咱们会在用户操做的时候,页面元素样式会进行相应的变化,这时候咱们就能够把要变化的样式写成一个class,操做class变化,就能实现大量样式的变化。正则表达式
(5)批量元素绑定事件,可使用事件委托。事件委托就是利用事件冒泡,只指定一个事件处理程序,就能够管理某一类型的全部事件。好比咱们有100个li,每一个li都要绑定click点击事件,就能够用事件委托。举一个例子:咱们须要给全部的button绑定click事件gulp
<div id="box"> <input type="button" id="add" value="添加" /> <input type="button" id="remove" value="删除" /> <input type="button" id="move" value="移动" /> <input type="button" id="select" value="选择" /> </div>
咱们有可能会这样写
window.onload = function(){ var Add = document.getElementById("add"); var Remove = document.getElementById("remove"); var Move = document.getElementById("move"); var Select = document.getElementById("select"); Add.onclick = function(){ alert('添加'); }; Remove.onclick = function(){ alert('删除'); }; Move.onclick = function(){ alert('移动'); }; Select.onclick = function(){ alert('选择'); } }
用事件委托就能够这样写:
window.onload = function(){ var oBox = document.getElementById("box"); oBox.onclick = function (ev) { var ev = ev || window.event; var target = ev.target || ev.srcElement; if(target.nodeName.toLocaleLowerCase() == 'input'){ switch(target.id){ case 'add' : alert('添加'); break; case 'remove' : alert('删除'); break; case 'move' : alert('移动'); break; case 'select' : alert('选择'); break; } } } }
并且使用事件委托,还有一个好处就是,当你添加一个新的button,同样的会绑定上click事件,这就是委托事件的好处。上面这样的写法是原生js的写法,jquery能够这样写:
$("#box").on("click","input",function(event){ var targetId = $(this).attr('id'); switch(targetId){ case 'add' : alert('添加'); break; case 'remove' : alert('删除'); break; case 'move' : alert('移动'); break; case 'select' : alert('选择'); break; } })
这样写就简便得多。
(6)避免没必要要的DOM操做,尽可能使用 ID 选择器:ID选择器是最快的,避免一层层地去查找节点。
(7)类型转换:把数字转换成字符串使用number + "" 。
虽然看起来比较丑一点,但事实上这个效率是最高的,性能上来讲:
("" + ) > String() > .toString() > new String()
(8)对字符串进行循环操做,譬如替换、查找,应使用正则表达式。由于自己JavaScript的循环速度就比较慢,而正则表达式的操做是用C写成的语言的API,性能很好。
(9)对象查询使用[""]查询要比.items()更快。这和前面的减小对象查找的思路是同样的,调用.items()增长了一次查询和函数的调用。
(10)浮点数转换成整型使用Math.floor()或者Math.round()。parseInt()是用于将字符串转换成数字,Math是内部对象,因此Math.floor()其实并无多少查询方法和调用的时间,速度是最快的。
关于js性能优化来讲,涉及到不少方面,特别是如今又出现不少的前端框架,优化方法又各有不一样。上面说的这些只是很浅显的东西,在开发中多注意一下就能够了,尽可能精简本身的代码。性能优化还须要继续深刻研究。