书读的越多而不加思考,你就会觉得你知道得很多;而当你读书而思考得越多的时候,你就会越清楚地看到,你知道得很少。——伏尔泰

优化网站性能方法,让快速访问网站不在是梦想

前端技术 码云 180℃ 0评论
优化网站性能方法,让快速访问网站不在是梦想

  互联网大家很熟悉,已经深入到我们生活的方方面面,使得用户对快速访问网页需求越来越高,对于企业来说用较低的成本较快的速度去留住用户流量就是在日益竞争的环境下取胜的关键,而做为网站建设者的我们,如何提高网站性能,成为急需去解决的问题,本文让你清楚认识到影响网站性能的原因,从而避免不利于网站性能的因素,同时借助Yslow工具快速找到问题所在,提高网站性能,让提高网站性能、快速访问网站不在是梦想。

尽可能减少HTTP的请求数

  什么是HTTP请求?官方的定义是:从客户端到服务端的请求消息。包括首行中,对资源的请求方法,资源的标识符及使用协议。这个解释很标准,但我们理解起来很困难,接下来我用菜鸟的原方式解释一下什么是HTTP请求,简单地说就是当你打开网页的时候,你所看到的图片、文字、多媒体等等,这一切内容都是你从服务器获取的,每一个内容的获取就是一个HTTP请求。

我用一张图来给大家解释一下:

尽可能减少HTTP的请求数

  从上图可以看出,当我们打开一个网页的时候,左边部分图片1、图片2、图片3等等,脚本文件javascript1、javascript2等等,样式文件css1、css2等等,这些都是要从服务器上来获取的,那么,每一个文件就是一个请求,当文件较多的时候,这个请求数就会很庞大。我们来看一下右边部分,这是一个优化后的请求,我们可以很直观的看到,我们将图片进行了合并,脚本文件进行了合并,样式文件进行了合并,这样当我们再次请求的时候,文字是一个请求,图片1、2、3合并成一个文件,脚本javascript1、2、3合并成一个文件,css1、2、3也合并成了一个文件,这样我们可以看到请求数相对于左边只有四个请求,这样对服务器的压力就会减轻了许多。这是一个靠我们智慧就能解决的问题

使用CDN(内容分发网络)

  什么是CDN?官方给我们很长的一个解释:内容分发网络,意思是尽可能避免互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳定。通过在网络各处放置节点服务器所构成的在现有的互联网基础之上的一层智能虚拟网络,CDN系统能够实时地根据网络流量和各节点的连接、负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上。其目的是使用户可就近取得所需内容,解决Internet网络拥挤的状况,提高用户访问网站的响应速度。

  很长的一个书面解释,还是用我们菜鸟的语言来解释一下吧,简单地说,在离你最近的地方,放置一台性能好链接顺畅的副本服务器,让你能够以最近的距离、最快的速度获取内容。同样让我们用一张图来解释一下:

使用CDN(内容分发网络)

  从图上可以很直观地看出,在没有使用CDN系统的时候,上面第一这台电脑当访问服务器的时候,要通过多个节点即三个小圈(红色的箭头走向),最后到达服务器获取内容。第二台电脑也要通过多个节点即两个小圈(蓝色箭头走向),来到大服务器获取内容。当我们使用CDN系统时,我们就可以把服务器制作成两个副本,将这两台副本服务器放置在离用户最近的地方,这样当用户访问这台服务器的时候,他就可以直接访问副本服务器来获取他想要的内容,这样从距离和速度上节省了很多,那么,很明显可以看到这需要添加服务器的,那么服务器是什么呢?服务器就是money,每一台服务器就是成本,所以这是一个靠money来解决的问题。当然,如果你money富裕的话这就不是问题了。

添加Expire/Cache-Control头

添加Expire/Cache-Control头

  如果apache(Web服务器)开启了expire模块,当浏览器发送资源请求的时候,apache返回资源的同时,会返回一个名为expire的http头,expire头的内容是一个时间值,值就是资源在本地的过期时间,存在本地。在本地缓存阶段,找到一个对应的资源值,当前时间还没超过资源的过期时间,就直接使用这个资源,不会发送http请求。

  Cache-Control是http协议中常用的头部之一,顾名思义,他是负责控制页面的缓存机制。如果该头部只是缓存,缓存的内容也会存在本地,操作流程和expire相似,但也有不同的地方,cache-control有更多的选项,而且也有更多的处理方式。

启用Gzip压缩

  什么是Gzip压缩?Gzip思想就是把文件先放到服务器压缩一遍然后再称述,这样可以显著的减少文件存储的大小,称述完毕之后,浏览器会重新对压缩过后的文件进行解压缩并执行。目前浏览器都能够很好的支持Gzip。

启用Gzip压缩

  在YAHOO也特别强调了,所有的文本内容进行Gzip压缩,这些文本包括HTML、PHP、JS、CSS、XML、TXT等等,使用Gzip的好处就是将稳健的体积变小,下面我们以79KB的文件为例,通过小图图表来说一下,假设原本一个79kb的js文件,在本地压缩后达到28kb,如果在服务器我们对79kb的原始的js文件进行Gzip压缩它的大小可以达到25kb,如果我们在服务器端,对已压缩过的js文件再进行Gzip压缩,那么它的大小就可以达到15kb,那么通过这个图表可以很明显看到这个原始js文件和这个通过Gzip压缩过的文件大小(最后小蓝柱)是相差好几倍的,这个在提升文件访问速度起着至关重要的作用,这个在我们服务器端配置一下就可以了,很简单。

启用Gzip压缩文件对比

将css放在页面最上面

  css层叠样式表(英文全称:CascadingStyleSheets),层叠意味着后面的css可以覆盖前面的css,级别高的css可以覆盖级别低的css,那么,为什么要把css放在页面最上边呢?其实是为了解决一个问题,在IE下,把css放在页面底部的问题,在于它禁止了网页内容的显示,IE阻止内容的显示以免重画页面元素,在低网速的条件下,用户打开的时候就只能看到空白页了。在Firefox浏览器里面,虽然不会阻止显示,但当css下载后页面部分元素可能需要重画,所以为了提高浏览器的性能,避免出现空白或闪烁的问题,我们应该将css放在页面额顶部head中,先进行加载和渲染,这样就避免上述提出的问题。

将script放在页面最下面

首先我们来了解一下dome的加载顺序,从下图可以看出,当我们打开网页的时候,加载顺序首先是读取HTML标签,然后是head标签,然后读取head标签内的meta标签,接着是title标签,然后是title内容,最后读取style标签,这时开始加载样式,加载完之后,开始解析这个样式,解析完之后继续向下读,读到了link标签,这会它会加载外部样式文件表进行解析,然后继续向下读,读到script标签,加载外部的script文件,解析这个文件并执行这个脚本文件,最后继续向下,读到body标签,然后读到里面的div标签,最后读到img标签加载外部头像,加载完毕,整个过程完成。

将script放在页面最下面

  了解完这个顺序后,我来解释一下为什么将script放在页面最下方,依照上面的例子我写一个死循环,当读到这儿的时候,浏览器会不停的执行它直到死机,所以在用这个脚本的时候大家要注意,我们只是在这里做一个测试,平时这个脚本是万万不能用的,用了以后IE奔溃了,我们也就彻底奔溃了!老板也疯了。如果按这样执行的话,在页面上打开就是一个空白,感兴趣的小伙伴下去可以试试,因为它执行for的时候浏览器一直在执行它,不会向下进行标签的读取,这样就会阻止下面内容的显示。

将script放在页面最下方

  同样我们将这段代码放在最下面前,依照dome加载顺序浏览器会依次向下逐步加载,将图片显示出来,当读到底部的script的for循环的时候,它同样的进行了一个不停地循环,虽然在这个时候浏览器死循环了,但是我们可以看到浏览器加载出来了,该显示的内容都显示出来了,通过这个实例很明显的看到将script标签放在页面底部的优势,它会先将页面呈现出来,不会让用户等的太久。

避免在CSS中使用Expressions

  什么是CSS Expressions?CSS Expressions俗称css表达式,是用来把css属性和javascript表达式关联起来,这里的css属性可以是元素固有的属性,也可以是自定义属性,就是说css属性后面可以是一段javascript表达式,css属性的值等于javascript表达式的计算结果。

避免在CSS中使用Expressions

  那么它的问题是什么呢,问题是CSS Expressions计算频率要比我们想象的多得多,不仅仅是在页面显示和缩放的时候,就是在我们页面滚动乃至鼠标移动的时候都会重新计算一次,给css表达式增加一个计数器可以跟踪表达式的计算频率,在页面上随便移动鼠标都可以达到一万次以上的计算量,说到这儿大家觉得不太容易理解,我们以一个实例看一下。

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>CSS Expressions测试</title>
    <script>
        var i = 0;
        function scare() {
            i++;
            document.getElementById('run').value = i;
            return;
        }
    </script>
    <style>
        ul a{width:expression(this.offsetWidth > 750 ? scare() : scare());}
    </style>
</head>
<body>
当鼠标移动时,CSS Expression计算了<input id="run" />次 <!--请在IE6、7下执行这段代码-->
<ul>
    <li><a href="http://baidu.com">aaa</a></li>
    <li><a href="http://baidu.com">bbb</a></li>
    <li><a href="http://baidu.com">cccc</a></li>
</ul>
</body>
</html>
CSS Expressions计算频率

  通过例子我们可以看到,当我们移动鼠标的时候,input内的数字在不断的变化,这就说明我们在使用CSS Expression的时候,在我们移动鼠标的时候,浏览器会不停的计算,最后严重影响浏览器的性能,影像用户的体验,所以我们应该避免使用CSS Expression。

把JS和CSS放到外部文件中

  关于这一点呢有很多争议,有人说把js和css全部提出来放到单独文件里引用,说这样会减少页面的体积,那反对的人就说了,应该写在页面里面减少请求数,这样可以提高页面渲染速度,加快页面呈献。其实在做这条优化的时候呢,我们应该灵活的使用,千万不可死背教条。

把JS和CSS放到外部文件中

  首先,我们分析一下提出来的好处与缺点,将css和js提出来的好处是一是提高了js和css的复用性,不用每个页面都去定义一次。二是减少页面体积,页面体积减少了那打开页面的速度当然就快了,脚本文件和样式文件被页面单独缓存。三是提高了js和css的可维护性,这一点虽然与性能无关,但其实也挺重要的,在后期的维护中如果前期的基础打得不好的话,后期维护就非常困难。

  缺点就是单独的文件增加了请求数,如果文件比较多的情况下,这个请求数肯定就会增加,影响网站的性能,其实这点也是可以通过缓存来优化的。

  说到它的好处与确定之后,那么是不是见到js和css就要单独提取出来呢?在实际的工作中并不是这样的,这里给大家总结一下在一些特殊的情况下还是要写在页面内的:

  一、当某个脚本和样式只应用于一个页面的时候,而且其他页面不会用到,这样放到内部的好处是大于提取出来的,因为相对于你的整个网站来说,只有一个页面使用那就没有必要再提取出来了。

  二、一个不经常被访问到的页面,也可以将css和js写在页面内部,因为你的这个页面只是偶尔打开使用,那就没有必要将css和js单独提取出来形成一个文件去使用,从而增加了文件系统的紊乱。

  三,脚本和样式非常少的情况,如果你的样式和脚本只有那么一两行或者三四行五六行,总之不多于20行,那你就没必要写到一个单独文件里了。

减少DNS查询

  怎么减少DNS查询?比如我们要访问www.a.com的时候,再打开这个页面之前,计算机是不知道www.a.com是什么,在哪里,它必须通过一种转换机制到达这个页面,这种机制能够将这个网址对应一个IP地址,一个计算机理解的地址,那计算机只认IP地址,它不懂域名是什么,然后通过这个IP地址对应到www.a.com这个网站,整个过程就是DNS查找过程。

怎么减少DNS查询

  既然是一个查找过程,那肯定是要消耗时间的,根据经验来说大概需要20毫秒的时间,在这个20毫秒的过程中呢,我们的浏览器是得不到任何资源的,所以这期间我们的浏览器是一片空白,大大家试想一下,如果我们的网站有很多这样的查找过程,对我们打开网站的性能肯定是有很大的影响的。所以我们要对这个过程进行缓存,缓存之后就可以减少这种查找过程,那么,由于现在浏览器都很智能,功能也强大了许多,自身都带了缓存的机制,所以对于操作系统的缓存这里不做介绍,因为现在浏览器自己都有缓存了。

  简单介绍浏览器的缓存,现在主流浏览器大家从下图可以看出三大阵营IE、Firefox、谷歌,三种浏览器缓存时间各有各的特点,IE浏览器默认情况下DNS缓存时间是30m,Firefox浏览器缓存时间大概是60s,谷歌与Firefox基本相同也是60s,具体他们时间长短为什么不同,我们只能推测大概和他们的浏览器厂商有关。

介绍浏览器的缓存

  缓存时间长短有什么不同呢?当缓存时间长的情况下,就会减少DNS重复查找,因为它被缓存了,浏览器会直接从缓存里面查找,节省时间。当缓存时间短的情况下,浏览器会及时的检测到指定网站IP地址的变化,保证访问的正确性,那在这个时间的长短上就各有各的好处。所以在缓存时间长短各有利弊的情况下,就导致各个浏览器厂商设置不同。那在做这条优化的时候呢,我们可以根据自己网站的特点来配置相应的技术点,比如我们采用是多域还是单域形式放置资源,比如多域我们可以把html文件、图片、js都分别提出来放在分别得域名下。单域就是把所有的文件、图片、脚本等等都放在一个服务器上。如果我们采用的是多域的方式的话,我们要考虑采用几个域名是最佳的点,不是越多越好,这个就需要大家通过实践来一点点感悟,感兴趣的小伙伴下去试试看看采用几个域名配置网站资源是最合适的。

缓存时间长短有什么不同呢

最小化 JavaScript 和 CSS

  最小化从字面上理解就是使javascript文件和css文件最小化,减小文件体积,从而提高在页面上的加载速度,那么通过什么方法可以减少文件体积呢?这里我介绍一下,一是可以去除一些不必要的空格,不必要的格式符,不必要的注释,简单理解就是代码的格式化,二是通过简写自定义的方法名、参数名压缩js脚本。

  这里我们以jQuery为例,我分别下载了两个jQuery版本,一个是压缩版的,一个是未压缩版的。

版本压缩对比

  首先我们从图中看到,未压缩的大小为276kb,一共有282944个字节,共10338行。压缩后的版本大小为94.1kb,一共有96381个字节,共5行。大家可以对比这三个值,压缩和未压缩是有很大差别的,所以建议大家在项目正式上线前,将你的javascript和css都进行一下压缩,使线上的版本是最轻量级的,这样可以大幅度提升我们网站的性能。

避免重定向

什么是重定向呢

  什么是重定向呢?就是原始请求被重新转向了其他的请求,通俗的说就是用户想访问的页面a被重新指向了页面b。那由于重定向有它存在的必要性,所以在http协议中有两种状态码标识这种情况,分别是301和302。

  301重定向表示用户请求的页面被移动到另外位置,比如a页面移动到b页面,那用户端收到这个反馈后,它会再发起另外一个请求去b.com去下载所需要的资源。

  302重定向表示用户所请求的页面被找到了但不在原始位置,所以服务器会回复它一个地址,用户端收到这个反馈后同样会发起另外一个请求,去服务器返回的地址中下载资源。

  上面的例子我们比较啰嗦解释301和302,其实301简单概述就是永久重定向,302表示临时重定向,这就很好理解了。

避免重定向

  有的小伙伴会有疑问了,301和302都是重定向,它们有什么区别呢?

  对用户来说没有什么区别,无论你是那种重定向你都是要重新请求下载资源,那为什么还要避免使用它呢?对搜索引擎来说,301和302就完全不一样了,现在我们上网几乎干什么都要去搜索一下,所以搜索引擎对于我们是不可缺少的部分,大家都知道搜索引擎会不定期的对网站进行扫描,SEO技术人员称蜘蛛爬网,为什么要定期去爬网呢,就是为了完善索引结构,让大家想找什么就找什么,所以它会定期的去爬网。若果你的网站使用了301永久重定向,蜘蛛爬虫看到你的网站指向了新域名,它就会智能分析永久记住你这个新域名从而删除你的旧地址,比如说用户通过搜索引擎搜索a.com,你通过跳转直接就到b.com了,而不会走从a再到b这样一个过程。302呢就不一样了,如果你使用的是302临时重定向,无论你从哪去跳,你都要先经过a再到b,它不会分析,就是机械的从a到b。

  通过上面对比301和302对搜索引擎来说301使搜索引擎更智能了。

  为什么要避免使用重定向?

为什么要避免使用重定向

  无论是301还是302它都增加了服务器到浏览器之间的往返次数,就是当用户发送访问a的请求时,服务器收到了,但由于a重定向了,重定向了b,所以服务器会返回一个重定向信息时301或者是302,并把这个信息写在header中,并在header中返回新的地址即b这个地址,但是body中是空白的,用户端在收到这个反馈后知道了原来地址改了,改到b了。所以用户的浏览器会再次请求到b,然后才打开网页下载资源。

  从上面整个过程可以看到,用户多了一层获知新地址的过程,这必然增加了浏览器到服务器建的返回次数,其实在上面就讲到了尽量减少http请求,所以在不得以的情况下避免使用它。

移除重复的脚本

  移除重复脚本,即不要使用重复的脚本,说到这儿可能有的小伙伴说了这不是废话吗,但究其原理你知道重复使用会出现什么问题吗,我们通过例子看一下。

<body>
<input type="text" id="test" value=""/>
<script>
    var number = 0;
</script>
<script src="test.js"></script>
</body>

   我在HTML页面上定义变量number等于0,新创建的js文件中给number执行++操作,然后将number变量增加后的值填入到我们input框内,最后在页面上引入改js文件。

number ++
document.getElementById('test').value = number;
移除重复的脚本

  注意我们的初始值number为0,我们在页面上看到input框内的值变为1,原因是我在js文件中执行了number++操作,它的值有0变为1,这是个正确的结果。但是由于我们不小心重复的引用了这个脚本,它会产生什么样的问题呢?

重复引入脚本

  从上图可以看出当我重复引入同一个脚本的时候,input框内的值变为2,由此大家可以看到当我引入一次js文件时,input框值是1,这是正确的,是我们想要的结果,但是当我们不小心重复引入js文件时,input框值变为2,所以通过这个例子大家也知道了浏览器不会智能的帮你识别重复脚本,他只会不断地根据你引入的js文件不断地做累加,其它脚本也会跟着不准确起来,所以在工作中大家要注意这一点。

配置实体标签(ETag)

  ETag全程EntityTag(实体标签),它包含在响应头部中,它属于http协议,自然所有web服务都支持它,那它能干点啥?它是使用特殊的字符串来标识某个请求资源版本,我们举个不太文雅例子,说一只小狗对着大树尿尿,这就是一种标识,一颗资源,一个版本,独一无二,这里只是属于它。这个比喻,只是方便让大家了解意思透彻一点。

配置实体标签(ETag)

  当用户通过浏览器来向服务器请求资源的时候,服务器会进行比较,如果两边的ETag一致,那就说明服务器的ETag和浏览器的一致,这就意味着该资源没有修改过,和之前一模一样。这时候服务器会返回一个304吗,告诉浏览器这里一致可以使用本地缓存的版本。

  让我们再用人类的对话再模拟一下下面的这个过程,那就是当浏览器向服务器请求资源的时候,服务器拿过来一看一对比,一样,它会告诉浏览器你都有了而且一样,不用再要了用你自己的吧,那这个信息返回给浏览器了,浏览器一听我有了,那我回去查查看吧,诶,确实有还真是一样,那就直接用我的吧。这样讲大家理解起来可能会简单多了。

  了解了这个过程,大家就知道了配置ETag的好处,它会帮助服务器减轻很多负担。

使用AJAX缓存

  Ajax即“AsynchronousJavascriptAndXML”(异步JavaScript和XML),它能够在不重新加载页面的情况下,使客户端与服务器进行交换数据,可使网站的内容分批加载,而且还可以局部更新。

  Ajax有两种方法,一种是POST请求,一种是GET请求。

  POST请求:每次都是需要报发给服务器处理的,服务器每次都会返回一个状态码200,从字面上我们发现有个关键词“每次”,就是这个“每次”决定了请求POST不被缓存。

  GET请求:除非你给它指定了一个不同的地址,否者同一个地址的ajax请求不会重复在服务器执行,它返回的状态码是304,说以它是可以被缓存的。

  说到这儿大家可能会产生一个新的疑问,那么什么时候使用POST请求呢?什么时候使用GET请求呢?解释着两个疑问就需要我们深入的研究一下POST和GET它们的功能,有什么区别,下面让我们用一张图表来对比一下POST和GET。

使用AJAX缓存,post和get区别对比

  通过上面这个图表上的对比,首先我们知道GET和POST的区别,那我们就知道了什么时候使用GET,什么时候使用POST,在理解了这个GET和POST的内在机制呢,我们就知道了什么时候对ajax进行缓存。推荐大家阅读我之前的一篇关于ajax的文章《jquery ajax如何高效的执行请求

  讲到这儿,大家可以再日常工作中具体情况具体使用上面的方法了,深刻的体会一下以上方法对自己网站新能的优化带来的好处。

转载请注明:码云笔记 » 优化网站性能方法,让快速访问网站不在是梦想

喜欢 (1)or分享 (0)
发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址