前端优化策略列举(二)

1、 使用json作为数据的交换格式
Json在浏览器解析的效率至少高于XML一个数量级,高级浏览器中内置的有生成和解析json的方法,IE6中要用额外的方法(http://json.org),不要用eval,容易引发性能和安全问题。

2、 尽可能对images和table设定宽高值
对图片和table是设定宽高,是考虑到如果浏览器能立刻知道图片或者tables的宽高,它就能够直接呈现页面而不需要通过计算元素大小后重绘,而且即便是图片损毁而没有展现,也不会进而破坏了页面本来的布局。

有一些应用场景需要注意:

  • 批量图片,图片源可控同时页面图片宽高值不可变,比如数据库有100张100*100的图片要在页面中全部展示,那么建议是都写上
    ”"
  • 批量图片,图片源不可控同时页面图片宽高值不可变,比如数据库有100张图片,而已知图片有的尺寸是97*100,有的100*105,而又不可能去一张张修改另存。这里视情况而定,根据图片尺寸与要求尺寸的偏离度,在保证图片不拉伸变形同时不影响页面布局的情况下,可以对图片单独设定宽度100,同时对其包裹的容器设定100*100的宽高来隐藏多出来的部分,注意不能同时设置宽高以防止变形。
  • 批量图片,图片源不可控,页面图片宽高值不定,比如数据库有100张各种尺寸偏差较大的,此时可不对图片设置宽高;

3、 拆离内容块
尽量用div取代tables,或者将tables打破成嵌套层次深的结构;
避免用这样的嵌套

<table>
    <table>
        <table>
            ...
        </table>
    </table>
</table>
采用下面的或者div重构:
<table></table>
<table></table>
<table></table>

4、 高效的CSS书写规则
众所周知,CSS选择符是从右向左进行匹配的。
通常一个图片列表的的小模块

<div id="box">
    <div class="hd">
        <h3>我的旅途</h3>
    </div>
    <div class="bd">
        <h4>旅途1</h4>
        <ul id="pics">
            <li>
                <a href="#pic" title=""><img src="" alt="" /> </a>
                <p>这是在<strong>图片1</strong></p>
            </li>
        </ul>
    </div>
</div>

为了代码上缩进后内层的整洁性,我们html有可能这样写之外,更喜欢看这样的css写法:

.box{border:1px solid #ccc }
.box .hd{border-bottom:1px solid #ccc }
.box .hd h3{color:#515151}
.box .bd{color:#404040 }
.box .bd ul{margin-left:10px}
.box .bd ul li{border-bottom:1px dashed #f1f1f1}
.box .bd ul li a{text-decoration:none}
.box .bd ul li a:hover{text-decoration:underline}
.box .bd ul li a img{border:1px solid #ccc}
.box .bd ul li p{text-align:left;}
.box .bd ul li p strong{color:#ff6600}

其实写到这里,问题已经显而易见了。深达五层抑或六层的嵌套,同时右边的选择符都是采用标签,在满足我们视觉平整与代码结构系统化的时候,付出的是性能的代价。

不做进一步的代码书写方式的探讨,受个人习惯与应用场景影响。这里对css选择符按照开销从小到大的顺序梳理一下:
· ID选择符 #box
· 类选择符 .box
· 类型选择符 div
· 相邻兄弟选择符 h4 + #pics
· 子选择符 #pics li
· 后代选择符 .box a{}
· 通配选择符 *
· 属性选择符 [href=”#pic”
· 伪类和伪元素 a:hover

参考《高性能网站建设-进阶指南》,有如下建议:
· 避免使用统配规则;
· 不要限定ID选择符;
· 不要限定类选择符;
· 让规则越具体越好;
· 避免使用后代选择符;
· 避免使用标签-子选择符;
· 质疑子选择符的所有用途;
· 依靠继承;

还要注意到,即便是页面加载后,当页面被触发引起回流(reflow)的时候,低效的选择符依然会引发更高的开销,显然这对于用户是不佳的体验。

5、Javascript 的性能优化点

  • 慎用Eval

谨记:有“eval”的代码比没有“eval”的代码要慢上 100 倍以上。主要原因是:JavaScript 代码在执行前会进行类似“预编译”的操作:

首先会创建一个当前执行环境下的活动对象,并将那些用 var 申明的变量设置为活动对象的属性,但是此时这些变量的赋值都是 undefined,并将那些以 function 定义的函数也添加为活动对象的属性,而且它们的值正是函数的定义。

但是,如果你使用了“eval”,则“eval”中的代码(实际上为字符串)无法预先识别其上下文,无法被提前解析和优化,即无法进行预编译的操作。所以,其性能也会大幅度降低。

  • 推荐尽量使用局部变量

JavaScript 代码解释执行,在进入函数内部时,它会预先分析当前的变量,并将这些变量归入不同的层级(level),一般情况下:

局部变量放入层级 1(浅),全局变量放入层级 2(深)。如果进入“with”或“try – catch”代码块,则会增加新的层级,即将“with”或“catch”里的变量放入最浅层(层 1),并将之前的层级依次加深。变量所在的层越浅,访问(读取或修改)速度越快,尤其是对于大量使用全局变量的函数里面。

  • 字符串数组方式拼接避免在IE6下的开销
var tips = 'tip1'+'tip2';

这是我们拼接字符串常用的方式,但是这种方式会有一些临时变量的创建和销毁,影响性能,尤其是在IE6下,所以推荐使用如下方式拼接:

var tip_array = [],tips;
tip_array.push('tip1');
tip_array.push('tip2');
tips = tip_array.join('');

当然,最新的浏览器(如火狐 Firefox3+,IE8+ 等等)对字符串的拼接做了优化,性能略快于数组的“join”方法。

以上仅列出三种常见的优化方法,仅抛砖以引玉石,更多的javascript优化点,比如避免隐式类型转换, 缩小对象访问层级,利用变量优化字符串匹配等大家可以继续深入挖掘;

6、DOM 操作优化

首先澄清两个概念——Repaint 和 Reflow:

Repaint 也叫 Redraw,它指的是一种不会影响当前 DOM 的结构和布局的一种重绘动作。如下动作会产生 Repaint 动作:

  • 不可见到可见(visibility 样式属性);
  • 颜色或图片变化(background, border-color, color 样式属性);
  • 不改变页面元素大小,形状和位置,但改变其外观的变化

Reflow 比起 Repaint 来讲就是一种更加显著的变化了。

它主要发生在 DOM 树被操作的时候,任何改变 DOM 的结构和布局都会产生 Reflow。
但一个元素的 Reflow 操作发生时,它的所有父元素和子元素都会放生 Reflow,最后 Reflow 必然会导致 Repaint 的产生。

举例说明,如下动作会产生 Reflow 动作:

  • 浏览器窗口的变化;
  • 一些改变页面元素大小,形状和位置的操作的触发
  • 改变文字大小
  • 内容的改变,如用户在输入框中敲字
  • 激活伪类,如:hover
  • 操作class属性
  • 脚本操作DOM
  • 计算offsetWidth和offsetHeight
  • 设置style属性

那么为了减少回流要注意哪些方式呢?

  • 不要通过父级来改变子元素样式,最好直接改变子元素样式,改变子元素样式尽可能不要影响父元素和兄弟元素的大小和尺寸

  • 尽量通过class来设计元素样式,切忌用style

参考:https://www.cnblogs.com/zhutao/p/6551216.html

通过 Reflow 和 Repaint 的介绍可知,每次 Reflow 比其 Repaint 会带来更多的资源消耗,因此,我们应该尽量减少 Reflow 的发生,或者将其转化为只会触发 Repaint 操作的代码。

var tipBox = document.createElement('div');
document.body.appendChild('tipBox');//reflow
var tip1 = document.createElement('div');
var tip2 = document.createElement('div');
tipBox.appendChild(tip1);//reflow
tipBox.appendChild(tip2);//reflow

如上的代码,会产生三次reflow,优化后的代码如下:

var tipBox = document.createElement('div');
      tip1 = document.createElement('div');
      tip2 = document.createElement('div');
tipBox.appendChild(tip1);
tipBox.appendChild(tip2);
document.body.appendChild('tipBox');//reflow

当然还可以利用 display 来减少reflow次数

var tipBox = document.getElementById('tipBox');
tipBox.style.display = 'none';//reflow
tipBox.appendChild(tip1);
tipBox.appendChild(tip2);
tipBox.appendChild(tip3);
tipBox.appendChild(tip4);
tipBox.appendChild(tip5);
tipBox.style.width = 120;
tipBox.style.height = 60;
tipBox.style.display = 'block';//reflow

DOM元素测量属性和方法也会触发reflow,如下:

var tipWidth = tipBox.offsetWidth;//reflow
      tipScrollLeft = tipBox.scrollLeft;//reflow
      display = window.getComputedStyle(div,'').getPropertyValue('display');//reflow

触发reflow的属性和方法大概有这些:

offsetLeft
offsetTop
offsetHeight
offsetWidth
scrollTop/Left/Width/Height
clientTop/Left/Width/Height
getComputedStyle()
currentStyle(in IE))

我们可以用临时变量将“offsetWidth”的值缓存起来,这样就不用每次访问“offsetWidth”属性。这种方式在循环里面非常适用,可以极大地提高性能。
如果有批量的样式属性需要修改,建议通过替换className的方式来降低reflow的次数,曾经有这样一个场景:有三个intput,分别对应下面三个图片和三个内容区域,第二input选中的时候,第二图片显示,其他图片隐藏,第二块内容显示,其他内容隐藏,直接操作DOM节点的代码如下

var input = [];
      pics = [];
      contents = [];
......
for(var i = 0;i<3;i++){
    input.onclick = function(e){
        show(pics,i);//reflow两次
        show(contents,i);//reflow两次
    }
}
function show(target,j){
    for(var i = 0,i<3;i++){
        target[i].style.display = 'none';//reflow  }
   target[j].style.display = 'block';//reflow
}

如果是通过css预先定义元素的隐藏和显示,通过对父级的className进行操纵,将会把reflow的次数减少到1次

pbox .pic,.pbox content{display:none}
J_pbox_0 .pic0,.J_pbox_0 .content0{diplay:block}
J_pbox_1 .pic1,.J_pbox_1 .content1{diplay:block}
J_pbox_2 .pic2,.J_pbox_2 .content2{diplay:block}
var input = [],
      parentBox = document.getELementById('J_Pbox');
......
for(var i = 0;i<3;i++)
    input[i].onclick = function(e){
      parentBox.className = 'pbox J_pbox_'+i;//reflow一次
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值