美文网首页我爱编程
Web性能优化笔记

Web性能优化笔记

作者: Scott1738 | 来源:发表于2018-04-01 17:00 被阅读0次

    网页性能优化的目的

    1. 减少服务器压力
    2. 增强用户体验,减少加载时间,通俗地说就是用户感觉打开你的网页很快,等待页面资源加载的时间很短

    方法

    回答这题的思路要从另一道面试题:从敲回车开始到页面展现这个过程发生了什么入手。以下是其中的一些过程:

    1. 看请求的html页面有没缓存,没有就进行下面步骤
    2. dns查询
    3. 建立TCP连接
    4. 发送HTTP请求
    5. 后台处理
    6. 接收响应
    7. 接收完成
    8. 读取html的DOCTYPE
    9. 逐行解析
    10. 看到<link href='#'>,<script src='#'>就会像服务器发起请求

    优化以上每个步骤,这样子整个web网页的性能就提高了

    减少dns查询

    你在浏览器地址栏输入网址,通过DNS查询得到网站真实IP。

    比如你的一个网站,需要向 baidu.com 请求一个js文件,向 bootcdn.cn 请求一个css文件,这样子就要进行2次dns查询(没有dns缓存的情况下),解决方法就是各种资源放在数量尽量少的域名下

    域名解析的流程

    1. 浏览器缓存 – 浏览器会缓存DNS记录一段时间
    2. 系统缓存 - 从 Hosts 文件查找是否有该域名和对应 IP。
    3. 路由器缓存 – 一般路由器也会缓存域名信息。
    4. ISP DNS 缓存 – 比如到电信的 DNS 上查找缓存。
    5. 如果都没有找到,则向根域名服务器查找域名对应 IP,根域名服务器把请求转发到下一级,知道找到 IP

    把资源分散到不同的域名。

    把资源分散到不同的域名允许你最大化并行下载数

    例如chrome,只能同时向一个域名最多发8个请求,把资源分散到不同的域名允许你最大化并行下载数,但这样子dns查询时间就变长,和前面的“减少dns查询“冲突了

    如果文件很少,例如只有3个文件,放在1个域名下,这样dns查询时间就很快,此时如果把这3个文件分散到更多的域名下,速度也不会提高,因为3个请求还没有达到chrome的只能同时向一个域名最多发请求的数量的极限

    如果文件很多,例如16个文件,还全部放在1个域名下,虽然dns查询时间很快,但请求时间会很慢,因为只能同时向一个域名最多发8个请求,那另外8个请求要等前面的请求发送完才能再发送

    懒加载和预加载

    懒加载就是例如打开一个网页,viewport以下的网页内容先不加载,等到用户滚动看到那部分内容再加载相应的资源,好处:节省CDN费用,降低服务器压力

    预加载就是预先加载用户即将要看到的内容,例如当你在第一页时就预先加载第二页的内容,这样子用户打开第二页的时候就不用等待加载时间

    使用CDN

    cdn即内容分发网络,例如谷歌的主服务器1在美国,在北京有个服务器2,服务器2不断地把主服务器1上的内容复制过来(可能说得不是很准确),这样子在北京访问谷歌,直接访问北京的服务器,比你访问美国的主服务器要快

    传输时gzip压缩资源

    HTTP/1.1开始,客户端通过http请求中的Accept-Encoding头部来提示支持的压缩:

    Accept-Encoding: gzip, deflate
    
    

    如果服务器看到这个头部,它可能会选用列表中的某个方法压缩要请求的资源。服务器通过响应中的Content-Encoding头部提示客户端:

    Content-Encoding: gzip
    
    

    客户端接收到响应后会解压缩

    gzip一般可减小响应的70%。尽可能去gzip更多(文本)类型的文件。html,脚本,样式,xml和json等等都应该被gzip,而图片,pdf等等不应该被gzip,因为它们本身已被压缩过,gzip它们只是浪费cpu,甚至增加文件大小。

    Cache-Control

     //后台代码
     if (path  ==='/js/main.js') {
       let  string  =    fs.readFileSync('./js/main.js', 'utf8');
       response.setHeader('Content-Type',   'application/javasript;charset=utf-8');
      response.setHeader('Cache-Control',   'max-age=30');
      response.write(string);
      response.end()
    }
    

    max-age=30指当第一次请求并下载/js/main.js后,30内遇到同样/js/main.js的请求(例如刷新当前页面),会从缓存里直接读取main.js,不会再向服务器发请求

    ETag

    在典型用法中,当一个URL被请求,Web服务器会返回资源和其相应的ETag值,它会被放置在HTTP的“ETag”字段中:

    ETag: "686897696a7c876b7e"
    
    
    

    然后,客户端可以决定是否缓存这个资源和它的ETag。以后,如果客户端想再次请求相同的URL,将会发送一个包含已保存的ETag和“If-None-Match”字段的请求。

    If-None-Match: "686897696a7c876b7e"
    
    

    客户端请求之后,服务器可能会比较客户端的ETag和当前版本资源的ETag。如果ETag值匹配,这就意味着资源没有改变,服务器便会发送回一个极短的响应,包含HTTP “304 未修改”的状态。304状态告诉客户端,它的缓存版本是最新的,并应该使用它。

    然而,如果ETag的值不匹配,这就意味着资源很可能发生了变化,那么,一个完整的响应就会被返回,包括资源的内容,就好像ETag没有被使用。这种情况下,客户端可以用新返回的资源和新的ETag替代先前的缓存版本。

    部分的后台Node.js示例代码:

    Snipaste_2018-04-01_16-59-49.png

    上图代码的md5(string)能输出string的md5值,用的是https://www.npmjs.com/package/md5 ,170k指的是string的大小

    用没有cookie的域名提供资源

    当浏览器请求静态图片并把cookie一起发送到服务器时,cookie此时对服务器没什么用处。所以这些cookie只是增加了网络流量。所以你应该保证静态资源的请求是没有cookie的。可以创建一个子域名来托管所有静态组件。

    比如,你域名是www.example.org,可以把静态资源托管在static.example.org。不过,你如果把cookie设置在顶级域名example.org下,这些cookie仍然会被传给static.example.org。这种情况下,启用一个全新的域名来托管静态资源

    另外一个用没有cookie的域名提供资源的好处是,某些代理可能会阻止缓存待cookie的静态资源请求。

    减少cookie体积

    1. 后端代码通过 Set-Cookie 响应头设置 Cookie的内容

    2. 浏览器得到 Cookie 之后,每次访问相同域名的网页时, 每次请求的header都会带上 Cookie,例如
      Cookie:sessionId=44438.40790818172

    http cookie的使用有多种原因,比如授权和个性化。cookie的信息通过http头部在浏览器和服务器端交换。尽可能减小cookie的大小来降低响应时间。

    • 消除不必要的cookie。
    • 尽可能减小cookie的大小来降低响应时间。
    • 注意设置cookie到合适的域名级别,则其它子域名不会被影响。

    选择<link>而不是@import

    之前的一个最佳原则是说CSS应该在顶部来允许逐步渲染。

    在IE用@import和把CSS放到页面底部行为一致,所以最好别用

    减少/最小化 http 请求数。

    有以下几个技术:

    • Combined files。合并文件,如合并js,合并css都能减少请求数。如果页面间脚本和样式差异很大,合并会更具挑战性。
    • CSS Sprites。雪碧图可以合并多个背景图片,通过background-imagebackground-position 来显示不同部分。
    • Inline images。使用data:url scheme来內连图片。

    使用外部JS和CSS。

    真实世界中使用外部文件一般会加快页面,因为JS和CSS文件被浏览器缓存了。內连的JS和CSS怎在每次HTML文档下载时都被下载。內连减少了http请求,但增加了HTML文档大小。另一方面,如果JS和CSS被缓存了,那么HTML文档可以减小大小而不增加HTTP请求。

    核心因素,就是JS和CSS被缓存相对于HTML文档被请求的频率。尽管这个因素很难被量化,但可以用不同的指标来计算。如果网站用户每个session有多个pv,许多页面重用相同的JS和CSS,那么有很大可能用外部JS和CSS更好。

    唯一例外是內连更被主页偏爱,如http://www.yahoo.com/
    主页每个session可能只有少量的甚至一个pv,这时候內连可能更快

    对多个页面的首页来说,可以通过技术减少(其它页面的)http请求。在首页用內连,初始化后动态加载外部文件,接下来的页面如果用到这些文件,就可以使用缓存了。

    压缩JS和CSS。

    压缩就是删除代码中不必要的字符来减小文件大小,从而提高加载速度。当代码压缩时,注释删除,不需要的空格(空白,换行,tab)也被删除。

    混淆是对代码可选的优化。它比压缩更复杂,并且可能产生bug。在对美国top10网站的调查,压缩可减小21%,而混淆可减小25%。

    除了外部脚本和样式,內连的脚本和样式同样应该被压缩。

    使用事件委托

    有时候页面看起来不那么响应(响应速度慢),是因为绑定到不同元素的大量事件处理函数执行太多次。这是为什么要使用事件委托

    另外,你不必等到onload事件来开始处理DOM树,DOMContentLoaded更快。大多时候你需要的只是想访问的元素已在DOM树中,所以你不必等到所有图片被下载。

    优化图片

    在设计师建好图片后,在上传图片到服务器前你仍可以做些事:

    • 检查gif图片的调色板大小是否匹配图片颜色数。
    • 可以把gif转成png看看有没有变小。除了动画,gif一般可以转成png8。
    • 运行pngcrush或其它工具压缩png。
    • 运行jpegtran或其它工具压缩jpeg。

    TCP 连接复用

    在 HTTP/1.0 时代,每一个请求都会重新建立一个 TCP 连接,一旦响应返回,就关闭连接。 而建立一个连接,则需要进行三次握手(https的话则是9次握手),这极大的浪费了性能

    因此 HTTP/1.1 新增了「keep-alive」功能,当浏览器建立一个 TCP 连接时,新的请求可以在上次建立的tcp连接之上发送,连接可以复用。。(现如今大多数浏览器默认都是开启的)

    HTTP 2.0 多路复用

    HTTP/2.0 时代拥有了「多路复用」功能,意思是: 在一条连接上,我可以同时发起无数个请求,并且响应可以同时返回。

    多个连接优化

    问题:一个1M的JS文件,如何下载比较快?

    1. 整个文件一个JS
    2. 拆分成两个500M的JS
    3. 拆分成4个250M的JS

    理论上答案是3.这样可以并行下载4个文件,减少了带宽的占据,但是增加了3次TCP请求时间,在下载时间和TCP请求时间的取舍上,就要具体情况具体测试分析了。

    如果是移动端就选择方案1,因为移动端对多文件下载不友好

    如果选择第3种方案,那么引生出另一个问题:为什么不分得更多?
    答:每个浏览器对并行下载有上限。每个域名限制最多同时进行N个下载线程。

    其他

    <link href=''><style><head>里面,因为无论放在那里都会阻塞html渲染(等到css文件下载并解析完才会显示html内容),所以还不如放head里面让css文件尽早下载

    js放body最后,这样子可以获取html节点,且能先尽早显示html页面

    chrome devtool的audits panel可以检测网站的性能优化情况

    参考资源:

    相关文章

      网友评论

        本文标题:Web性能优化笔记

        本文链接:https://www.haomeiwen.com/subject/vhkacftx.html