本来在那片编写可维护性代码文章后就要总结这篇代码性能文章的,耽搁了几天,本来也是决定每天都要更新一篇文章的,因为以前欠下太多东西没总结,学过的东西没去总结真的很快就忘记了,记录一下在你脑力留下更深的印象,特别是这些可维护性代码,性能什么的,当在你脑子里形成一种习惯了,那你就牛了!这里也要给初学者一个建议:多总结你学过的东西,因为这其实也是在学习新知识! 好,进入我们的主题:如何提高JS代码的性能。
1.优化DOM交互
DOM与我们的页面紧密相关,浏览器渲染页面也就是在渲染解析后的DOM元素,DOM操作与交互要消耗大量的时间,因为它们往往需要重新渲染整个页面或者一部分。进一步说,看似细微的一些操作也可能需要花很多时间来执行,因为DOM要处理的信息非常多,因此我们应该尽可能地优化与DOM相关的操作,加快浏览器对页面的渲染!为什么有些DOM操作会影响页面性能,可以查看我写的一些关于浏览器原理的文章:
ok,优化DOM操作,我们主要有一些几种方式:
1.1 最小化现场更新
什么是DOM的现场更新:需要对DOM部分已经显示的页面的一部分的显示立即更新。但是,每一个更改,不管是插入单个字符,还是一处整个片段,都有一定的性能惩罚,因为浏览器需要重新计算无数尺寸以进行更新(相关知识请阅读:)。所以,现场更新进行的越多,代码执行所花的时间就越长,反之代码执行越快,如下:
var list = document.getElementById('mylist'), item, i; for(i = 0; i < 10; i++){ item = document.creatElement('li'); list.appendChild(item); item.appendChild(document.creatTextNode('item' + i)); }
这段代码为列表mylist添加了10个项目,没添加一个项目都要进行2次的现场更新:添加元素和添加文本节点,所以这个操作一个需要完成20个现场更新,每个更新都会损失性能,可见这样的代码运行起来是相对缓慢的。
解决的方法是使用文档碎片间接地更改DOM元素:
var list = document.getElementById('mylist'), fragment = document.creatDocumentFragment(), item, i; for(i = 0; i < 10; i++){ item = document.creatElement('li'); fragment .appendChild(item); item.appendChild(document.creatTextNode('item' + i)); } list.appendChild(fragment);
像这样的代码只需进行一次的现场更新。记住,当给appendChild()传入文档碎片是,只有文档碎片中的子节点才会被添加到目标元素,碎片本身不会被添加。
现在,你应该明白你用循环直接进行DOM节点的增删查改是多么对不起浏览器的事了吧 `(∩_∩)′ 。
1.2 使用 innerHTML
除了上面代码中使用的creatElement() 和 appendChild()结合的方法创建DOM元素之外,还有通过给innerHTML赋值来创建。对于小的DOM更改而言,两种方法的效率其实差不多,但对于大量的DOM节点的更改,后者要比前者快得多!为啥捏?
因为当我们给innerHTML赋值时,后台会创建一个HTML解析器,然后使用内部的DOM调用来创建DOM结构,而非基于Javascript的DOM调用,由于内部方法是编译好的而非解释执行的,所以执行代码的速度要快很多!
用innerHTML改写上面的例子:
var list = document.getElementById('mylist'), html = '', //声明一个空字符串 i; for(i = 0; i < 10; i++){ html += '<li>item' + i + '</li>'; } list.innerHTML = html; // 这里记得innerHTML后面的HTML四个字母都要大写!
这种方式同样也只进行了一次的现场更新,并且性能要比上一种方式要好!虽然在字符串的链接上有点性能损失。
1.3 使用事件代理/事件委托
事件处理程序为web应用提供交互能力,因此许多开发人员会不分青红皂白地向页面中添加大量的处理程序,有个问题就是一个页面上的事件处理程序数量将直接关系到页面的整体运行性能。为什么捏?
首先,事件处理程序对应至少一个函数,JS中每个函数都是对象,都会占用内存,内存中的对象越多,性能就越差。
其次,我们必须事先指定所有事件处理程序,这就导致了DOM访问次数增多,会延迟整个页面的交互就绪时间,页面响应用户操作变得相对缓慢。
所以减少事件处理程序同样也可以让我们的页面更牛畅!使用事件委托势在必得啊!
事件委托的原理其实就是事件冒泡,只指定一个事件处理程序就可以管理某一类型操作的所有事件。例如:click事件会一直冒泡到document层次,也就是说我们不必为每个元素添加事件,只需在较高的层次的元素上添加事件处理程序即可,然后利用事件对象(event)的属性或方法去判断当前点击的元素,然后做出相应的响应。这个我就不展开讲了,初学者可以自行查阅事件冒泡知识。
2.作用域很重要