Javascript收集

前端性能优化(总结)

2017-06-30  本文已影响22人  woow_wu7
(1)减少HTTP请求次数
举例:
如有5个css文件,则需要发出5次http请求,第一次访问页面需要等待很长世间。
如合并成1个css文件,则发出1次http请求,节省网络请求时间,加快页面的加载。
(1)Expires 表示存在时间:
允许客户端在这个时间之前不去检查(发请求),等同max-age的效果。但是如果同时存在
则被Cache-Control的max-age覆盖。
(2)Cache-control用于控制HTTP缓存:
1.原理
通过HTTP的Expires和Cache-Control,使已缓存资源不再发起http请求。
(将静态内容设为永不过期,或者很长时间后才过期。)
2.应用
通过HTTP的META设置expires和cache-control
<meta http-equiv="Cache-Control" content="max-age=7200" />
<meta http-equiv="Expires" content="Mon, 20 Jul 2009 23:00:00 GMT" />
上述设置仅为举例,实际使用其一即可。
这样写的话仅对该网页有效,对网页中的图片或其他请求无效,并不会做任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
<img width=”50″ height=”50″ src=“hahah.jpg” alt=”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);
        }
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);
     var buf = [];
        for (var i = 0; i < 100; i++) {
            buf.push(i.toString());
        }
        var all = buf.join("");
with (a.b.c.d) {
            property1 = 1;
            property2 = 2;
        }
        //可以替换为:
        var obj = a.b.c.d;
        obj.property1 = 1;
        obj.property2 = 2;
 //避免多次取值的调用开销
        var h1 = element1.clientHeight + num1;
        var h2 = element1.clientHeight + num2;
        //可以替换为:
        var eleHeight = element1.clientHeight;
        var h1 = eleHeight + num1;
        var h2 = eleHeight + num2;
 if (a > b) {
            num = a;
        } else {
            num = b;
        }
        //可以替换为:
        num = a > b ? a : b;
    var num = 0;
        setTimeout('num++', 10);
        //可以替换为:
        var num = 0;
        function addNum() {
            num++;
        }
        setTimeout(addNum, 10);
   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('<p>' + i + '</p>');
        }
        document.body.innerHTML = html.join('');
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);
 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"
   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
 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
       function create() {
            var gc = document.getElementById('GC');
            for (var i = 0; i < 5000; i++) {
                var el = document.createElement('div');
                el.innerHTML = "test";
                //下面这句可以注释掉,看看浏览器在任务管理器中,点击按钮然后刷新后的内存变化
                gc.appendChild(el);
            }
        }
//糟糕的全局变量和全局函数
var current = null;
function init(){
//...
}
function change() {
    //...
}
function verify() {
    //...
}
--
--
//解决办法有很多,Christian Heilmann建议的方法是:
//如果变量和函数不需要在“外面”引用,那么就可以使用一个没有名字的方法将他们全都包起来。(闭包)
(function(){
var current = null;
function init() {
    //...
}
function change() {
    //...
}
function verify() {
    //...
}
})();
--
--
//如果变量和函数需要在“外面”引用,需要把你的变量和函数放在一个“命名空间”中
//我们这里用一个function做命名空间而不是一个var,因为在前者中声明function更简单,而且能保护隐私数据
myNameSpace = function() {
    var current = null;

    function init() {
        //...
    }
    function change() {
        //...
    }
    function verify() {
        //...
    }
//所有需要在命名空间外调用的函数和属性都要写在return里面
    return {
        init: init,
        //甚至你可以为函数和属性命名一个别名
        set: change
    };
};

-循环引用
如果循环引用中包含DOM对象或者ActiveX对象,那么就会发生内存泄露。内存泄露的后果是在浏览器关闭前,即使是刷新页面,这部分内存不会被浏览器释放。

简单的循环引用: var el = document.getElementById('MyElement');
        var func = function () {
            //…
        }
        el.func = func;
        func.element = el;
但是通常不会出现这种情况。通常循环引用发生在为dom元素添加闭包作为expendo的时候。
function init() {
            var el = document.getElementById('MyElement');
            el.onclick = function () {
                //……
            }
        }
        init();
init在执行的时候,当前上下文我们叫做context。
这个时候,context引用了el,el引用了function,function引用了context。这时候形成了一个循环引用。
//解决方如下
//解决方如下
//解决方如下
1)  置空dom对象
 function init() {
            var el = document.getElementById('MyElement');
            el.onclick = function () {
                //……
            }
        }
        init();
        //可以替换为:
        function init() {
            var el = document.getElementById('MyElement');
            el.onclick = function () {
                //……
            }
            el = null;
        }
        init();
将el置空,context中不包含对dom对象的引用,从而打断循环应用。
如果我们需要将dom对象返回,可以用如下方法:
  function init() {
            var el = document.getElementById('MyElement');
            el.onclick = function () {
                //……
            }
            return el;
        }
        init();
        //可以替换为:
        function init() {
            var el = document.getElementById('MyElement');
            el.onclick = function () {
                //……
            }
            try {
                return el;
            } finally {
                el = null;
            }
        }
        init();
//解决方如下
//解决方如下
//解决方如下
2)  构造新的context
   function init() {
            var el = document.getElementById('MyElement');
            el.onclick = function () {
                //……
            }
        }
        init();
        //可以替换为:
        function elClickHandler() {
            //……
        }
        function init() {
            var el = document.getElementById('MyElement');
            el.onclick = elClickHandler;
        }
        init();
把function抽到新的context中,这样,function的context就不包含对el的引用,从而打断循环引用。

上一篇 下一篇

猜你喜欢

热点阅读