前端优化
前端优化
未完待续!!!!
ipconfig /displaydns
查看操作系统自身的DNS缓存,在命令行中输入:ipconfig /displaydns ,点击回车就可以看见。
减少HTTP请求
巧用css,字体图标、雪碧图减少图片的请求数量
- 比如使用css绘制三角形
<div class="triangle"></div>
.triangle{
width: 60px;
height: 60px;
background-color: slategray;
border-top: 30px solid saddlebrown;
border-right: 30px solid salmon;
border-bottom: 30px solid sandybrown;
border-left: 30px solid seagreen;
}
/*绘制向上三角形*/
.triangle{
width: 0;
height: 0;
background-color: transparent;
border-top: 0 solid saddlebrown;
border-right: 30px solid transparent;
border-bottom: 30px solid sandybrown;
border-left: 30px solid transparent;
}
绘制宽高都为60px,边框为30px的正方形样式:
将宽高都设置为0时的样式:
绘制向上的三角形,将左右border的颜色设置为透明,将上border的大小设置为0(根据绘制的方向不同设置其他三个方向的border):
- 使用雪碧图
使用雪碧图把一些背景图片整合到一张图片上,根据background-position定位图片的位置,显示不同的背景图片, 一般情况下,雪碧图需要保存为PNG-24的文件格式。
使用雪碧图的规则:
- 静态图片,不随用户信息的变化而变化;
- 小图片,图片容量比较小,大图不建议拼成雪碧图;
- 加载量比较大的图片,比如网站中常用的下载,搜索等小图标。
雪碧图的优点: 减少加载网页图片时对服务器的请求次数;提高页面的加载速度。
雪碧图的缺点: 内存使用;拼图维护比较麻烦;使CSS的编写变得困难。
快速制作雪碧图的网站:https://www.toptal.com/developers/css/sprite-generator
代码实例:
<div class="container">
<div class="img_item"></div>
<div class="img_item"></div>
</div>
.img_item{
width: 100px;
height: 100px;
background-image: url(http://img95.699pic.com/element/40104/8112.png_300.png);
background-repeat: no-repeat;
float: left;
margin-left: 20px;
}
.img_item:nth-child(1){
background-position: 0 15%;
}
.img_item:nth-child(2){
background-position: 50% 15%;
}
.img_item:nth-child(3){
background-position: 100% 15%;
}
雪碧图:
执行结果:
合并,压缩资源
能合并的css和js文件尽量合并,减少文件的数量,同时使用相关工具对资源进行压缩。
HTML、css、js代码压缩:http://tool.oschina.net/jscompress?type=2
HBuilder编辑器可以压缩css和js代码,压缩后的文件为文件名.min.css/js.
前端在切图时将不需要背景透明的图片保存为jpg格式,以此来减小图片的大小,也可以使用专门的图片压缩工具将图片压缩。
瀑布式的图片布局使用懒加载
图片懒加载实例可参考我的另一篇博客:https://blog.****.net/weixin_38233549/article/details/89245663
HTML优化
使用语义化标签
标签语义化的好处:
- HTML结构清晰,便于阅读
- 减少class类名(比如header,nav,footer等可以不设置类名也能快速找到)
- 搜索引擎可以根据标签的语言确定上下文和权重问题
- 移动设备能够更完美的展现网页(对css支持较弱的设备)
- 便于团队维护和开发
<body>
<header>我是头部</header>
<nav>
<!-- 下面li和a的快捷写法:li*2>a 然后点击tab键 -->
<li><a href="">标签一</a></li>
<li><a href="">标签二</a></li>
</nav>
<main>
<section>
<h2>我是内容一的标题</h2>
</section>
</main>
<footer>我是尾部</footer>
</body>
减少页面中DOM元素的数量
尽量使用伪元素
伪元素无法使用js获取到,或者增、删、改一个伪元素,伪元素的优点在于制造视觉上的效果,但是简化了页面的HTML结构,减少了DOM元素的个数。
过多的DOM元素对于页面的加载时一种负担,尽量简化页面,减少DOM元素。
页面DOM元素个数的获取:
document.getElementsByTagName('*').length
注:伪元素并不是完全使用js获取不到,可以使用getComputerStyle去获取,因为getComputerStyle可以传递第二个参数,以表示伪元素。
<h2 class="title1">我是内容一的标题</h2>
.title1::after{
content: '我是title1的after伪元素';
width: 272px;
line-height: 30px;
display: inline-block;
margin-left: 34px;
}
var title1_after=window.getComputedStyle(document.getElementsByClassName('title1')[0],':after');
//var title1_after=window.getComputedStyle(document.querySelector('.title1'),':after');
console.log(title1_after)
css优化
将css放在head标签中
如果将样式表放在底部,会阻止浏览器中的内容逐步出现。为了避免当样式变化时重绘页面元素,浏览器会阻塞内容逐步呈现,造成“白屏”。
虽说将样式表放在头部对于实际页面加载的时间并不能造成太大影响,但是这会减少页面首屏出现的时间,使页面内容逐步呈现,改善用户体验,防止“白屏”。
使用link代替@import引用css样式表
link和@import的区别
- link是HTML标签。除了可以加载css,还可以定义RSS等事物,@import属于css范畴,只能加载css
- link引入样式表在页面载入的同时进行加载,@import需要页面完全载入再加载,增加加载时间,影响页面展示
- link是HTML标签,五兼容问题,@import低版本浏览器不支持
- link支持使用js去改变DOM元素的样式,@import不支持
css精简
例如:css中的0不写单位
footer,header{
margin:0px;
margin:0;/*推荐*/
}
例如:将相同的样式合并
header{
width: 100%;
height: 80px;
line-height: 80px;
text-align: center;
font-size: 20px;
}
footer{
width: 100%;
height: 80px;
line-height: 80px;
text-align: center;
font-size: 20px;
}
/*将相同的样式合并*/
footer,header{
width: 100%;
height: 80px;
line-height: 80px;
text-align: center;
font-size: 20px;
}
例如:合并属性以及颜色使用缩写等
header{
border-bottom: 1px solid #eee;/*推荐*/
/*不推荐*/
border-bottom-width: 1px;
border-bottom-style: solid;
border-bottom-color: #eee;
}
避免css表达式
/*根据时间修改背景颜色,请使用IE5、IE6、IE7测试*/
footer{
background-color: expression((new Date()).getHours()%2 ? "#B8D4FF" : "#F08A00" );
}
能用css和html完成的就不要使用js控制
例如导航的下拉菜单(布局时要显示的和触发的必须是相邻元素):
<nav>
<li>
<a href="">标签一</a>
<div class="dropdown_menu">
<p><a href="">菜单一</a></p>
</div>
</li>
<li>
<a href="">标签二</a>
<div class="dropdown_menu">
<p><a href="">菜单二</a></p>
</div>
</li>
<div class="clearfix"></div>
</nav>
nav>li{
width: 180px;
height: 40px;
list-style: none;
float: left;
text-align: center;
}
.clearfix{
clear: both;
}
nav>li>a{
text-decoration: none;
display: inline-block;
width: 100%;
line-height: 40px;
}
.dropdown_menu{
width: 100%;
padding:20px;
box-sizing: border-box;
display: none;
cursor: pointer;
}
nav>li>a:hover +.dropdown_menu{
display: block;
}
.dropdown_menu:hover{
display: block;
}
js优化
将脚本放在body的底部
虽然浏览器是可以并发请求的,提升加载资源的速度,但是外链脚本在加载时却会阻塞其他资源,例如在脚本加载完成之前,它后面的图片、样式以及其他脚本都处于阻塞状态,直到当前脚本加载完成后才会开始加载其他的内容。如果将脚本放在比较靠前的位置,则会影响整个页面的加载速度从而影响用户体验。
合并、压缩js文件
加载的js文件数也会影响性能,一次加载100kb比加载4个25kb的快
延迟脚本
defer 属性规定是否对脚本执行进行延迟,直到页面加载为止,defer在页面的onload事件处理器执行之前调用,不会阻塞其他进程,所以如果将脚本放在head中,又不想影响其他内容或文件加载时可以使用defer属性让脚本延迟加载。
defer测试HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>测试defer</title>
<script defer src="defer_test1.js"></script>
<script defer src="defer_test2.js"></script>
</head>
<body>
<div class="dropdown_menu">一</div>
<div class="dropdown_menu">二</div>
<div class="dropdown_menu">三</div>
<script>
function closureTest(){
var count=1;
count++;
return (function(){
var countArr=[];
if(count%2===0){
countArr.push(count)
}
return countArr
})()
}
console.log(closureTest())//[2]
</script>
</body>
</html>
defer_test1.js代码:
(function(){
function getNavItem(){
var dropdown_menu=document.querySelectorAll('.dropdown_menu');
var len=dropdown_menu.length
for(var i=0;i<len;i++){
console.log(dropdown_menu[i].innerText)
}
}
getNavItem();
})()
defer_test2.js代码:
(function(){
console.log(2)
})()
测试结果,即使defer_test2.js的代码少,执行速度快,但是因为defer,他必须等待DOM和defer_test1.js加载完才能加载:
减少作用域链的操作
尽量使用局部变量
function getNavItem(){
var li =document.querySelectorAll('li');
var dropdown_menu=document.querySelectorAll('.dropdown_menu');
console.log(dropdown_menu);
for(var i=0;i<li.length;i++){
console.log(li[i].innerHTML);
}
}
getNavItem();
在上述代码中,document是一个全局变量,每次都需要找到全局作用域才能找到,如果使用局部变量暂时储存一下,这样document就变成了局部变量,查找速度明显的比全局变量快。
function getNavItem(){
var doc=document;
var li =doc.querySelectorAll('li');
var dropdown_menu=doc.querySelectorAll('.dropdown_menu');
console.log(dropdown_menu);
for(var i=0;i<li.length;i++){
console.log(li[i].innerHTML);
}
}
getNavItem();
比如:循环节点集合是将length保存
function test(){
var doc=document;
var li=doc.querySelectorAll('li');
var offsetArr=[];
var len=li.length;
var offsetLeft=li[0].offsetLeft;
for(var i=0;i<len;i++){
offsetArr.push(li[i].offsetLeft);
}
}
test()
闭包虽好,但不要滥用
闭包的作用在于可以让子级作用域访问父级作用域中的变量,同时这些变量在不同的闭包中是不可见的,这就导致了在查找某个变量时,如果当前作用域找不到,就要往父级作用域查找,一级一级的往上找,直到找到或者到全局作用域也没找见时为止。因此闭包嵌套的越深,那么变量的查找时间就越长。
function closureTest(){
var count=1;
count++;
return (function(){
var countArr=[];
if(count%2===0){
countArr.push(count)
}
return countArr
})()
}
console.log(closureTest())//[2]
在上述代码中使用了闭包,变量count查找时间比countArr时间长,我们可以将count作为参数传给匿名函数,也可以在匿名函数中使用局部变量存储count,减少count的查找时间。
function closureTest(){
var count=1;
count++;
return (function(){
var countArr=[];
if(count%2===0){
countArr.push(count)
}
return countArr
})(count)
}
console.log(closureTest())//[2]
减少代码耦合
代码耦合会导致牵一发而动全身,不易于维护和修改。
避免全局耦合
全局耦合就是几个类、模块共用了全局变量或者全局数据结构,有的变量甚至跨越好几个文件,在加载或使用时就要一个文件的去找,增加解析时间。
避免HTML/CSS/JS的耦合
使用js去控制css在开发中很常见也是不可避免的,在遇到这种情况是尽量使用增加或者删除一个类名来实现(如果需要使用到js中计算的结果等情况就可以直接在js中修改css),这样样式还是在css文件中,后期的代码维护也简单一些。
比如:表格的头部在滑到顶部时吸顶,使用fixed布局,但是这样当表格的宽度大于浏览器的可视宽度时thead不能随着滚动而滚动,这时就需要计算横向滑动的距离去改变thead的left值,使其和tbody在滑动是保持一致。
减少重复代码
减少重复使用到的代码,先是封装成一个函数,再到封装成一个模块,最后可以封装成一个插件。
推荐使用 ===
- 当进行双等号比较时候: 先检查两个操作数数据类型,如果相同, 则进行===比较, 如果不同, 则愿意为你进行一次类型转换, 转换成相同类型后再进行比较
- ===比较是否相等时,类型不同就直接返回false。
if('只比较值是不是相等,不关心数据类型'){
'使用==比较'
}else{
if('数据类型确定'){
'使用==或===比较'
}else{
'使用===比较'
}
}
如果只判断值是否相等就使用双等号,是确定了数据类型则使用双等号比较,如果数据类型不明确则使用三等号比较。
双等号在jslint的检查中会报错:
改为===时显示OK:
注:jslint的使用
- 安装
打开命令行输入:npm install -g jslint - 使用
命令行输入:jslint jslint_test.js,jslint_test.js是要检测的js文件名(在这个文件的目录下)
合并表达式
代码行数越少,执行速度越快。
- 将简单的if-else语句换成三元运算符
function test(){
var flag=0;
if(null === undefined){
flag=1;
}else{
flag=0;
}
return flag;
}
function test(){
return null === undefined?1:0
}
- 使用连等
连等是利用赋值运算表达式返回所赋的值,并且执行顺序是从右到左的。
function test(){
var num=0;
for(var i=0;i<10;i++){
if(num=i+2*i++>10){
console.log('我出界了,咋办');
}else{
console.log('好险我还在10以内');
}
}
}
使用es6简化代码
- 使用箭头函数替代小函数
setTimeout(function(){console.log('1')},200);
setTimeout(()=>console.log('1'),200);//使用箭头函数,代码少了
2.使用反引号拼接字符串
var html='';
var doc=document;
for(var i=0;i<2;i++){//使用引号拼接
html=html+
'<li>'+
'<a href="">标签'+i+'</a>'+
'<div class="dropdown_menu">'+
'<p><a href="">菜单'+i+'</a></p>'+
'</div>'+
'</li>';
}
for(var i=0;i<2;i++){//使用反引号拼接相同的代码结构,比使用引号拼接的代码简洁
html=html+
`<li>
<a href="">标签`+i+`</a>
<div class="dropdown_menu">
<p><a href="">菜单`+i+`</a></p>
</div>
</li>`;
}
doc.getElementsByTagName('nav')[0].innerHTML=html;
减少回流和重绘
回流
当渲染树的一部分或全部的元素因改变了自身的宽高,布局,显示或隐藏,或者元素内部的文字结构发生变化 导致需要重新构建页面的时候,回流就产生了
重绘
当一个元素自身的宽高,布局,及显示或隐藏没有改变,而只是改变了元素的外观风格的时候,就会产生重绘。例如你改变了元素的background-color…
回流必定会引起重绘,但重绘不一定会引起回流。
css触发回流的属性
分类 | 相关属性 |
---|---|
盒子模型 | width、height、margin、padding、border、display... |
定位、浮动 | top、right、bottom、left、position、float、clear... |
文字结构 | text-align、font-size、font-weight、font-family、line-height、vertical-align、white-space、overflow... |
css触发重绘的属性
重绘 |
---|
color、border-style、border-radius、visibility、display、text-decoration、background、background-image、background-color、background-position、background-repeat、 background-size、outline、outline-color、outline-style、outline-width、box-shadow... |
减少回流和重绘的措施
css减少回流
- 避免使用table布局
js减少回流
- 使用js设置样式时一次性修改,不要一项一项的改,最好增加删除class
var doc=document;
var footer=doc.querySelector('footer');
footer.style.border='1px solid #eee';
footer.style.backgroundColor='skyblue';
footer.style.fontWeight='bolder';
//推荐下方的写法
footer.style.cssText=`
background-color: skyblue;
border: 1px solid #eee;
font-weight: bolder;`;