前端性能优化(DOM篇)

简介: 原文链接:https://segmentfault.com/a/1190000000490322 缓存DOM对象 JavaScript的DOM操作可以说是JavaScript最重要的功能,我们经常要根据用户的操作来动态的增加和删除元素,或是通过AJAX返回的数据动态生成元素。

原文链接:https://segmentfault.com/a/1190000000490322

缓存DOM对象

JavaScript的DOM操作可以说是JavaScript最重要的功能,我们经常要根据用户的操作来动态的增加和删除元素,或是通过AJAX返回的数据动态生成元素。比如我们获得了一个很多元素的数组data[],需要将其每个值生成一个li元素插入到一个id为container的ul元素中,最简单(最慢)的方式是:

var liNode, i, m;
for (i = 0, m = data.length; i < m; i++) {
    liNode = document.createElement("li"); liNode.innerText = data[i]; document.getElementById("container").appendChild(liNode); } 

这里每一次循环都会去查找id为container的元素,效率自然非常低,所以我们需要将元素在循环前查询完毕,在循环中仅仅是引用就行了,修改代码为:

var ulNode = document.getElementById("container");
var liNode, i, m;
for (i = 0, m = data.length; i < m; i++) { liNode = document.createElement("li"); liNode.innerText = data[i]; ulNode.appendChild(liNode); } 

缓存DOM对象的方式也经常被用在元素的查找中,查找元素应该是DOM操作中最频繁的操作了,其效率优化也是大头。在一般情况下,我们会根据需要,将一些频繁被查找的元素缓存起来,在查找它或查找它的子孙元素时,以它为起点进行查找,就能提高查找效率了。

在内存中操作元素

由于DOM操作会导致浏览器的回流,回流需要花费大量的时间进行样式计算和节点重绘与渲染,所以应当尽量减少回流次数。一种可靠的方法就是加入元素时不要修改页面上已经存在的元素,而是在内存中的节点进行大量的操作,最后再一并将修改运用到页面上。DOM操作本身提供一个创建内存节点片段的功能:document.createDocumentFragment(),我们可以将其运用于上述代码中:

var ulNode = document.getElementById("container");
var liNode, i, m;
var fragment = document.createDocumentFragment(); for (i = 0, m = data.length; i < m; i++) { liNode = document.createElement("li"); liNode.innerText = data[i]; fragment.appendChild(liNode); } ulNode.appendChild(fragment); 

这样就只会触发一次回流,效率会得到很大的提升。如果需要对一个元素进行复杂的操作(删减、添加子节点),那么我们应当先将元素从页面中移除,然后再对其进行操作,或者将其复制一个(cloneNode()),在内存中进行操作后再替换原来的节点

一次性DOM节点生成

在这里我们每次都需要生成节点(document.createElement("li")),然后将其加入到内存片段中,我们可以通过innerHTML属性来一次性生成节点,具体的思路就是使用字符串拼接的方式,先生成相应的HTML字符串,最后一次性写入到ul的innerHTML中。修改代码为:

var ulNode = document.getElementById("container");
var fragmentHtml = "", i, m; for (i = 0, m = data.length; i < m; i++) { fragmentHtml += "<li>" + data[i] + "</li>"; } ulNode.innerHTML = fragmentHtml; 

这样效率也会有提升,不过手动拼写字符串是相当麻烦的一件事

通过类修改样式

有时候我们需要通过JavaScript给元素增加样式,比如如下代码:

element.style.fontWeight = 'bold';
element.style.backgroundImage = 'url(back.gif)';
element.style.backgroundColor = 'white';
element.style.color = 'white';
//... 

这样效率很低,每次修改style属性后都会触发元素的重绘,如果修改了的属性涉及大小和位置,将会导致回流。所以我们应当尽量避免多次为一个元素设置style属性,应当通过给其添加新的CSS类,来修改其CSS

.element {
    background-image: url(back.gif); background-color: #fff; color: #fff; font-weight: 'bold'; /*...*/ } 
element.className += " element";

通过事件代理批量操作事件

还是之前那个ul和添加li,如果我们需要给每个li都绑定一个click事件,就可能写出类似如下代码:

var ulNode = document.getElementById("container");
var fragment = document.createDocumentFragment(); var liNode, i, m; var liFnCb = function(evt){ //do something }; for (i = 0, m = data.length; i < m; i++) { liNode = document.createElement("li"); liNode.innerText = data[i]; liNode.addEventListener("click", liFnCb, false); fragment.appendChild(liNode); } ulNode.appendChild(fragment); 

这里每个li元素都需要执行一次addEventListener()方法,如果li元素数量一多,就会降低效率。所以我们可以通过事件代理的方式,将事件绑定在ul上,然后通过event.target来确定被点击的元素是否是li元素,同时我们也可以使用innerHTML属性一次性创建节点了,修改代码为:

var ulNode = document.getElementById("container");
var fragmentHtml = "", i, m; var liFnCb = function(evt){ //do something }; for (i = 0, m = data.length; i < m; i++) { fragmentHtml += "<li>" + data[i] + "</li>"; } ulNode.innerHTML = fragmentHtml; ulNode.addEventListener("click", function(evt){ if(evt.target.tagName.toLowerCase() === 'li') { liFnCb.call(evt.target, evt); } }, false); 

这样事件绑定的代码就只要执行一次,可以监听所有li元素的事件了。当然如果需要移除事件回调函数,我们也不需要循环遍历所有的li元素,只需要移除ul元素上的事件处理就行了

目录
相关文章
|
22天前
|
前端开发 JavaScript UED
深入了解前端性能优化:提高用户体验的关键
【10月更文挑战第9天】深入了解前端性能优化:提高用户体验的关键
41 5
|
27天前
|
缓存 前端开发 JavaScript
前端性能优化:从基础到进阶的实践指南
【10月更文挑战第4天】在前端开发中,性能优化至关重要,尤其随着Web应用的复杂化,用户对加载速度和响应性的要求日益提高。本文从基础知识入手,涵盖代码压缩、图片优化及缓存策略,并深入探讨代码拆分、懒加载和Web Workers等进阶技巧,帮助开发者全面提升Web应用的用户体验。通过这些方法,不仅能够减少页面加载时间,还能提升响应性和渲染性能,为用户提供更流畅的使用体验。
52 1
|
27天前
|
缓存 前端开发 JavaScript
前端性能优化:提升用户体验的关键策略
【10月更文挑战第4天】前端性能优化:提升用户体验的关键策略
46 1
|
3天前
|
缓存 前端开发 JavaScript
前端性能优化:Webpack与Babel的进阶配置与优化策略
【10月更文挑战第28天】在现代Web开发中,Webpack和Babel是不可或缺的工具,分别负责模块打包和ES6+代码转换。本文探讨了它们的进阶配置与优化策略,包括Webpack的代码压缩、缓存优化和代码分割,以及Babel的按需引入polyfill和目标浏览器设置。通过这些优化,可以显著提升应用的加载速度和运行效率,从而改善用户体验。
16 5
|
5天前
|
缓存 监控 前端开发
前端工程化:Webpack与Gulp的构建工具选择与配置优化
【10月更文挑战第26天】前端工程化是现代Web开发的重要趋势,通过将前端代码视为工程来管理,提高了开发效率和质量。本文详细对比了Webpack和Gulp两大主流构建工具的选择与配置优化,并提供了具体示例代码。Webpack擅长模块化打包和资源管理,而Gulp则在任务编写和自动化构建方面更具灵活性。两者各有优势,需根据项目需求进行选择和优化。
25 7
|
4天前
|
缓存 前端开发 JavaScript
前端工程化:Webpack与Gulp的构建工具选择与配置优化
【10月更文挑战第27天】在现代前端开发中,构建工具的选择对项目的效率和可维护性至关重要。本文比较了Webpack和Gulp两个流行的构建工具,介绍了它们的特点和适用场景,并提供了配置优化的最佳实践。Webpack适合大型模块化项目,Gulp则适用于快速自动化构建流程。通过合理的配置优化,可以显著提升构建效率和性能。
13 2
|
11天前
|
缓存 前端开发 JavaScript
前端性能优化:打造流畅用户体验的秘籍
【10月更文挑战第20天】前端性能优化:打造流畅用户体验的秘籍
24 3
|
10天前
|
存储 缓存 算法
前端算法:优化与实战技巧的深度探索
【10月更文挑战第21天】前端算法:优化与实战技巧的深度探索
10 1
|
10天前
|
缓存 前端开发 JavaScript
如何优化前端资源
如何优化前端资源
|
11天前
|
监控 前端开发 JavaScript
前端性能优化:打造流畅用户体验的秘籍
【10月更文挑战第20天】前端性能优化:打造流畅用户体验的秘籍
21 2