性能优化策略分类
- 网页资源请求与加载类
- 网页渲染类
- JavaScript 脚本类
HTML 中的 CSS 和JavaScript
-
内联
优点:
减少HTTP请求
缺点:
1. 没办法复用
2. 使得 HTML 文件变大,加载时间变长
3. 代码都写到 HTML 文件中,不利于后期的维护 ?
工程化的手段可以解决这个问题
源码到可以上线的代码 -
通过外部文件引入
优点:
1. 很好的复用代码
有效利用浏览器的静态资源缓存
2. 代码分离,利于后期维护
缺点:
增加了 HTTP 请求
建议,首屏必备的 css 和 js 用内联的方式引入,其他的则通过外部文件引入
CSS 和 JS 的位置问题
CSS 应放在 head 中,越早加载越好,因为在渲染页面时,CSS 样式,越早加载,页面样式越早出现
JS 一般都放在 body 的最后,不过也有特殊情况,希望越早执行越好的要放在前面,比如屏幕适配的代码,首屏获取数据的代码
避免重复的资源请求
同一个 CSS,JS 不应重复引入
文件的压缩
要对文件进行压缩 html,css,js 都需要进行压缩处理
文件的合并
对太小的文件进行合并,不要让文件太大,也不要让文件太小
文件的缓存
后端开启一定的配置,是浏览器正确的缓存 css 或 js 文件
图片和其他优化
HTTP 请求大
图片压缩处理
使用更高压缩比格式的图片
webp
尽量少用图片
使用图标字体代替图片图标
CSS 画图
HTTP 请求多
合理使用 base64 内嵌图片
合并静态资源图片
雪碧图
手动
DOM 树不要嵌套太多层
这样浏览器解析起来会非常耗时
链接不能留空
a,img,link,script,iframe 的 src 或 href 属性不能留空,因为如果留空浏览器也会进行寻找,会耗时
不建议使用慢元素
table, iframe 会将元素中的内容读取完毕才会显示,所以会耗时
主要内容要写在前面
由于 html 要从前向后解析,所以主要内容要写在前面,次要内容要写在后面
css 选择器优化
/* 可以用一个id 或 class 选择就不要添加其他修饰 */
div#slider.slider {} /* 不推荐用这种写法 */
.slier {} /* 推荐这种写法 */
一般 id 是给 js 用的,class 是给 css 用的,因为 css 要考虑复用的问题(id选择器效率会比较高)
/* css 选择时在语义不冲突的情况下,尽量保持简单 */
.slider .slider-item-container .slider-item .slider-link .slider-img {} /* 不推荐这样写 */
.slider-img {} /* 推荐这种写法 */
css 有权重,在覆盖原属性时,权重越低越好覆盖
* {} /* 不推荐,因为 css 会解析所有的元素 */
.slider-item-container * {} /* 这也不推荐,因为 css 会从右往左解析,仍然会解析全部元素,效率非常低 */
[class*="slider-indicator"] {}
[class~="slider-indicator"] {}
[class^="slider-indicator"] {}
[class$="slider-indicator"] {}
/**
* 这几种选择器也会有一点性能问题,如果你的网站对性能要求非常高的话,产生了性能问题可以考虑这方面问题
**/
css属性
- 提取公共属性
可以减小文件的大小,就能减小 http 请求大小,也方便统一修改
/* 不推荐 */
.slider {
width: 100%;
height: 100%;
}
.slider-item-container {
width: 100%;
height: 100%;
}
/* 推荐 */
.slider,
.slider-item-container {
width: 100%;
height: 100%;
}
- 合并可以合并的属性
/* 不推荐 */
.slider {
margin-top: 10px;
margin-bottom: 10px;
margin-left: 20px;
margin-right: 20px;
}
/* 推荐 */
.slider {
margin: 10px 20px 10px 20px;
}
css其他优化
-
避免使用 @import url(‘base.css’);
-
移动端尽量使用 flex 布局,因为 float 布局会比 flex 布局消耗性能多
DOM 操作优化
DOM 操作是一种很耗性能的行为
优化方向
(1) 加快单次 DOM 操作
(2) 减少 DOM 操作的次数
- 获取 DOM 元素
能用 id 尽量用 id 因为用 id 获取 DOM 元素速度最快
但是不适合用 id 时就不要用了,比如需要复用时 - 能从父元素开始查找,就不要用 document 查找
sliderEl.querySelector('.slider-item-container'); // 较好
document.querySelector('.slider-item-container'); // 不推荐
- 将 DOM 元素缓存起来,这样在以后的使用中可以使用缓存,从而减少了 DOM 操作
const itemContainer = sliderEl.querySelector('.slider-item-container');
- 可以生成节点碎片,不在页面上渲染会提高效率
克隆节点会比创建节点提高效率
var indicatorItemFragment = document.createDocumentFragment();
var spanEl = document.createElement('span');
for (var i = 0; i < sliderItem.length; i++) {
var indicatorItem = spanEl.cloneNode(true);
indicatorItem.className = 'slider-indicator';
indicatorItemFragment.appendChild(indicatorItem);
}
indicatorContainer.appendChild(indicatorItemFragment);
sliderEl.appendChild(indicatorContainer);
- 变更属性尽量使用 className 增删 class 进行,尽量避免用 style 直接修改属性
应为要避免 css 重排和重绘
有些浏览器每一步 style 修改属性就 重排或重绘一次,这样如果修改多个属性就会多次重排和重绘,有部分浏览器会将写在一起的属性统一重排和重绘,但有部分不会这样
事件优化
-
事件委托
见文章 DOM 事件 -
事件截流
scroll, resize, mousemove, touchmove 触发事件可以使用事件截流
var timer = null;
window.addEventListener('scroll', () => {
clearTimeout(timer);
setTimeout(() => {
console.log('scroll');
}, 100);
});
图片的按需加载
const lazyLoadClass = '.lazyload-img';
const imgArr = Array.prototype.slice.call(document.querySelectorAll(lazyLoadClass));
const isVisibleArea = (el) => {
const info = el.getBoundingClientRect();
return info.bottom > 0 && info.top < window.innerHeight && info.right > 0 && info.left < window.innerWidth;
}
const lazyLoadImgs = () => {
for(let i = 0; i < imgArr.length; i++) {
if (isVisibleArea(imgArr[i])) {
imgArr[i].src = imgArr[i].dataset.src;
imgArr.splice(i, 1);
i--;
}
}
}
lazyLoadImgs();
let timer = null;
window.addEventListener('scroll', () => {
clearTimeout(timer);
setTimeout(() => {
lazyLoadImgs();
}, 100);
});