前端性能优化(总结)

(1)减少HTTP请求次数
  • 尽量合并图片、CSS、JS。
举例:
如有5个css文件,则需要发出5次http请求,第一次访问页面需要等待很长世间。
如合并成1个css文件,则发出1次http请求,节省网络请求时间,加快页面的加载。
  • Expires和Cache-Control (多由服务器端去设置)
    浏览器在第一次访问页面时向服务器请求资源,并缓存起来,下次再访问时会判断在缓存中是否已有该资源且有没有更新过,如果已有该资源且未更新过,则直接从浏览器缓存中读取。
(1)Expires 表示存在时间:
允许客户端在这个时间之前不去检查(发请求),等同max-age的效果。但是如果同时存在
则被Cache-Control的max-age覆盖。
(2)Cache-control用于控制HTTP缓存:
1.原理
通过HTTP的Expires和Cache-Control,使已缓存资源不再发起http请求。
(将静态内容设为永不过期,或者很长时间后才过期。)
2.应用
通过HTTP的META设置expires和cache-control


上述设置仅为举例,实际使用其一即可。
这样写的话仅对该网页有效,对网页中的图片或其他请求无效,并不会做任cache。
(2)对HTTP传输进行压缩 (gzip压缩)(多由服务端去设置)

即在js,css、图片等资源已经压缩的基础上,在HTTP传输过程中的再次压缩。

1.原理
客户端:通过Accept-Encoding头来声明浏览器支持的压缩方式,
服务端:通过content-Encoding来启用压缩,配置压缩的文件类型,压缩方式。
(当客户端的请求到达服务器,服务器对资源进行压缩后,返回给客户端,客户端按照相应的方式进行解析。)

客户端(HTTP请求头)——accept-encoding: gzip, deflate, sdch, br
服务器(HTTP响应头)——content-encoding:gzip
2.应用
以tomcat服务器的配置为例:
找到tomcat安装目录下的conf文件夹下的server.xml文件,进行如下配置,重启tomcat即可:
① compress="on" :表示开启压缩。
② compressionMinSize="2048":表示对大于2KB的文件进行压缩
③ compressableMimeType="text/html,text/xml,application/
JavaScript,text/css,text/plain,image/png,image/jpeg,image/gif" //表示将进行压缩的文件类型

注意:不应该对图片进行再压缩,因为图片本身已经被压缩过
(如果再进行gzip压缩,可能得到的结果是和图片本身大小相差不大,纯粹是浪费服务器的CPU资源来做无用功。)

3.优缺点
对HTTP传输内容进行压缩的优、缺点:
① 优点:减少HTTP响应时间,提升传输效率。
② 缺点:压缩过程占用服务器额外的CPU周期,客户端也要对压缩文件进行解压缩,这也需要占用部分时间。
(3)将CSS文件放在顶部
原理:
将CSS放在底部,页面可以逐步呈现,
但在CSS下载并解析完毕后,已经呈现的文字和图片就要需要根据新的样式重绘,这是一种不好的用户体验。
(4)将javascript放在底部
原理:
script没有async和defer时,JS文件将在下载后立即执行。这种情况下,script放在顶部会阻塞页面呈现,
在网速慢的情况下会导致“白屏”,直到脚本下载完毕才继续呈现页面。因此,script放在底部可以让页面尽快呈现。

script全部放在head中会出现的问题:
在需要操作body中的某元素时,可能找不到该元素,因此,若要放在head中,
一般需要绑定一个监听windows.onload=function(){ ... },
当文档全部解析完之后再执行script代码。
(5)cookie优化
cookie原理:

1、去除没有必要的cookie,如果网页不需要cookie就完全禁掉。

2、将cookie的大小减到最小。
由于cookie在访问对应域名下的资源时都会通过HTTP请求发送到服务器,
因此,减小cookie的大小,能减小HTTP请求报文的大小,提高响应速度。

3、设置合适的过期时间,较长的过期时间可以提高响应速度。
给cookie添加一个过期时间,则cookie信息将存储到硬盘上,即使浏览器退出Cookie还会存
在。只要Cookie未被清除且还在过期时间内,该Cookie就会在访问对应域名时发送给服务器。

4、通过使用不同的domain减少cookie的使用。
cookie在访问对应域名下的资源时都会通过HTTP请求发送到服务器,但在访问一些资源,如js,css和图片时,
大多数情况下cookie是多余的,可以使用不同的domain来存储这些静态资源,这样访问这些资源时就不会发送
多余的cookie,从而提高响应速度。
(6)可缓存的AJAX
异步请求同样的造成用户等待,所以使用ajax请求时,要主动告诉浏览器如果该请求有缓存就去请求缓存内容。
如下代码片段: cache:true就是显式的要求如果当前请求有缓存的话,直接使用缓存
$.ajax({
     url : 'url',
     dataType : "json",
     cache: true,   //如果有缓存,就直接使用缓存
     success : function(son, status){    
      }
(7)使用GET来完成AJAX请求
当使用XMLHttpRequest时,浏览器中的POST方法是一个“两步走”的过程:首先发送文件头,然后才发送数据。

因此使用GET获取数据时更加有意义。
(8) 避免404
比如外链的css或者js文件出现问题返回404时,会破坏浏览器对文件的并行加载。

并且浏览器会把试图在返回的404响应内容中找到可能有用的部分当作JavaScript代码来执行。
(9)避免使用CSS表达式
例如:
font-color: expression( (new Date()).getHours()%3 ? “#FFFFFF" : “#AAAAAA" );

这个表达式会持续的在页面上计算样式,影响页面的性能。并且css表达式只被IE支持。


(10)避免空的src和href
当link标签的href属性为空、script标签的src属性为空的时候,浏览器渲染的时候会把当前页面的URL

作为它们的属性值,从而把页面的内容加载进来作为它们的值。所以要避免犯这样的疏忽
(11)缩小favicon.ico并缓存

https://www.ico.la/ 提供的在线免费创建favicon.ico文件服务.

(1)使它尽量在1KB左右。使用ico格式,不要使用png,jpg等其他格式。
(2)将该文件放在单独的主机中,例如 images.mydomain.com . 这样可以避免在请求该文件时发送cookie. 
(3)缓存
(12)不要在HTML中缩放图片
需要的图片尺寸是50* 50,不要用500*500的图片在img中设置成50*50
”hahaha”
(13)使用CDN
网站上静态资源即css、js全都使用cdn分发,图片亦然。
(14)减少dom元素数量
原理:
减少DOM数量,就会减少浏览器的解析负担
(15)不要使用滤镜
IE独有属性AlphaImageLoader用于修正7.0以下版本中显示PNG图片的半透明效果。
这个滤镜的问题在于浏览器加载图片时它会终止内容的呈现并且冻结浏览器。在每一个元素(不仅仅是图片)
它都会运算一次,增加了内存开支,因此它的问题是多方面的。完全避免使用AlphaImageLoader的最好方法
就是使用PNG8格式来代替,这种格式能在IE中很好地工作。如果你确实需要使用AlphaImageLoader,
请使用下划线_filter又使之对IE7以上版本的用户无效。



Javascript优化篇

  • 避免全局查找
    在一个函数中会用到全局对象存储为局部变量来减少全局查找,因为访问局部变量的速度要比访问全局变量的速度更快些
  function search() {
            //当我要使用当前页面地址和主机域名
            alert(window.location.href + window.location.host);
        }
        //最好的方式是如下这样  先用一个简单变量保存起来
        function search() {
            var location = window.location;
            alert(location.href + location.host);
        }
  • 定时器
    如果针对的是不断运行的代码,不应该使用setTimeout,而应该是用setInterval,因为setTimeout每一次都会初始化一个定时器,而setInterval只会在开始的时候初始化一个定时器
var timeoutTimes = 0;
        function timeout() {
            timeoutTimes++;
            if (timeoutTimes < 10) {
                setTimeout(timeout, 10);
            }
        }
        timeout();
        //可以替换为:
        var intervalTimes = 0;
        function interval() {
            intervalTimes++;
            if (intervalTimes >= 10) {
                clearInterval(interv);
            }
        }
        var interv = setInterval(interval, 10);
  • 字符串连接
    如果要连接多个字符串,应该少使用+=,如
    s+=a;
    s+=b;
    s+=c;
    应该写成s+=a + b + c;
    而如果是收集字符串,比如多次对同一个字符串进行+=操作的话,最好使用一个缓存,使用JavaScript数组来收集,最后使用join方法连接起来
     var buf = [];
        for (var i = 0; i < 100; i++) {
            buf.push(i.toString());
        }
        var all = buf.join("");
  • 避免with语句
    和函数类似 ,with语句会创建自己的作用域,因此会增加其中执行的代码的作用域链的长度,由于额外的作用域链的查找,在with语句中执行的代码肯定会比外面执行的代码要慢,在能不使用with语句的时候尽量不要使用with语句。
with (a.b.c.d) {
            property1 = 1;
            property2 = 2;
        }
        //可以替换为:
        var obj = a.b.c.d;
        obj.property1 = 1;
        obj.property2 = 2;
  • 数字转换成字符串
    般最好用”" + 1来将数字转换成字符串,虽然看起来比较丑一点,但事实上这个效率是最高的,性能上来说:
    (“” +) > String() > .toString() > new String()

  • 重复使用的调用结果,事先保存到局部变量

 //避免多次取值的调用开销
        var h1 = element1.clientHeight + num1;
        var h2 = element1.clientHeight + num2;
        //可以替换为:
        var eleHeight = element1.clientHeight;
        var h1 = eleHeight + num1;
        var h2 = eleHeight + num2;
  • 条件分支
    (1)将条件分支,按可能性顺序从高到低排列:可以减少解释器对条件的探测次数
    (2)在同一条件子的多(>2)条件分支时,使用switch优于if:switch分支选择的效率高于if,在IE下尤为明显。4分支的测试,IE下switch的执行时间约为if的一半。
    (3)使用三目运算符替代条件分支
 if (a > b) {
            num = a;
        } else {
            num = b;
        }
        //可以替换为:
        num = a > b ? a : b;
  • 避免双重解释
    如果要提高代码性能,尽可能避免出现需要按照JavaScript解释的字符串,也就是
    (1)尽量少使用eval函数
    使用eval相当于在运行时再次调用解释引擎对内容进行运行,需要消耗大量时间,而且使用Eval带来的安全性问题也是不容忽视的。
    (2)不要使用Function构造器
    不要给setTimeout或者setInterval传递字符串参数
    var num = 0;
        setTimeout('num++', 10);
        //可以替换为:
        var num = 0;
        function addNum() {
            num++;
        }
        setTimeout(addNum, 10);
  • 使用一次innerHTML赋值代替构建dom元素
    对于大的DOM更改,使用innerHTML要比使用标准的DOM方法创建同样的DOM结构快得多。
   var frag = document.createDocumentFragment();
        for (var i = 0; i < 1000; i++) {
            var el = document.createElement('p');
            el.innerHTML = i;
            frag.appendChild(el);
        }
        document.body.appendChild(frag);
        //可以替换为:
        var html = [];
        for (var i = 0; i < 1000; i++) {
            html.push('

' + i + '

'); } document.body.innerHTML = html.join('');
  • 使用DocumentFragment优化多次append
    一旦需要更新DOM,请考虑使用文档碎片来构建DOM结构,然后再将其添加到现存的文档中。
for (var i = 0; i < 1000; i++) {
            var el = document.createElement('p');
            el.innerHTML = i;
            document.body.appendChild(el);
        }
        //可以替换为:
        var frag = document.createDocumentFragment();
        for (var i = 0; i < 1000; i++) {
            var el = document.createElement('p');
            el.innerHTML = i;
            frag.appendChild(el);
        }
        document.body.appendChild(frag);
  • 浮点数转换成整型
    很多人喜欢使用parseInt(),其实parseInt()是用于将字符串转换成数字,而不是浮点数和整型之间的转换,我们应该使用Math.floor()或者Math.round()

  • 使用firstChild和nextSibling代替childNodes遍历dom元素

  • ==和===的区别
    避免在if和while语句的条件部分进行赋值,如if (a = b),应该写成if (a == b),但是在比较是否相等的情况下,最好使用全等运行符,也就是使用===和!==操作符会相对于==和!=会好点。==和!=操作符会进行类型强制转换

 var valueA = "1";
        var valueB = 1;
        if (valueA == valueB) {
            alert("Equal");
        }
        else {
            alert("Not equal");
        }
        //output: "Equal"
        if (valueA === valueB) {
            alert("Equal");
        }
        else {
            alert("Not equal");
        }
        //output: "Not equal"
  • 何时用单引号,何时用双引号
    虽然在JavaScript当中,双引号和单引号都可以表示字符串, 为了避免混乱,我们建议在HTML中使用双引号,在JavaScript中使用单引号,但为了兼容各个浏览器,也为了解析时不会出错,定义JSON对象时,最好使用双引号

  • 使用return语句需要注意
    一条有返回值的return语句不要用()括号来括住返回值,如果返回表达式,则表达式应与return关键字在同一行,以避免压缩时,压缩工具自动加分号而造成返回与开发人员不一致的结果

   function F1() {
            var valueA = 1;
            var valueB = 2;
            return valueA + valueB;
        }
        function F2() {
            var valueA = 1;
            var valueB = 2;
            return
            valueA + valueB;
        }
        alert(F1());  //output: 3 
        alert(F2());  //ouput: undefined
  • 每条语句末尾须加分号
    在if语句中,即使条件表达式只有一条语句也要用{}把它括起来,以免后续如果添加了语句之后造成逻辑错

  • 使用+号时需谨慎
    JavaScript 和其他编程语言不同的是,在 JavaScript 中,’+'除了表示数字值相加,字符串相连接以外,还可以作一元运算符用,把字符串转换为数字。因而如果使用不当,则可能与自增符’++’混淆而引起计算错误

 var valueA = 20;
        var valueB = "10";
        alert(valueA + valueB);     //ouput: 2010 
        alert(valueA + (+valueB));  //output: 30 
        alert(valueA + +valueB);    //output:30 
        alert(valueA ++ valueB);     //Compile error
  • switch语句相对if较快
    通过将case语句按照最可能到最不可能的顺序进行组织

  • 位运算较快
    当进行数字运算时,位运算操作要比任何布尔运算或者算数运算快

  • 解耦CSS/JavaScript
    显示问题的唯一来源应该是CSS,行为问题的唯一来源应该是JavaScript,层次之间保持松散耦合才可以让你的应用程序更加易于维护,所以像以下的代码element.style.color=”red”尽量改为element.className=”edit”,而且不要在css中通过表达式嵌入JavaScript

  • 解耦HTML/JavaScript
    JavaScript和HTML的紧密耦合:直接写在HTML中的JavaScript、使用包含内联代码的

你可能感兴趣的:(前端性能优化(总结))