[转] 《高性能HTML5》读后整理的Web性能优化内容

  • 读后感

        先说说《高性能HTML5》这本书的读后感吧,我的以为这本书前两章跟书的标题彻底搭不上关系,或者说只能算是讲解了“高性能”这三个字,HTML5彻底不见踪迹。我的以为做者应该首先把HTML5的大菜拿出来说一讲,再去分析性能优化的内容,这样才会有吸引力。由于只是在线试读,没有机会看后面的内容,因此不胡乱评价了。javascript

 

        虽然我以为这本书没说到点子上,但仍是从“高性能”方面学到了不少东西------又一次扩大了知识面!之前,我一直认为一套架构稳定、后台高质量的代码就能让系统高效,但读完这本书两章内容以后,发现前端有那么多能够提升性能的方式,一直被我轻视的前台技术也能有这么“花哨”,又一次井底之蛙了- -||。css

 

        在看完这两章内容以后,我意犹未尽,因而乎从网上搜索关键字“Java Web高性能”,在IBM社区找到两篇不错的文章,而让人更意外的是我发现那两篇文章的内容跟《高性能HTML5》前两章高度类似,不知道是谁抄袭谁的,你们能够鉴别下真伪,下面附上地址。html

        http://dl2.iteye.com/upload/attachment/0097/9373/b0e69540-e703-3530-81bb-c93de7b850a6.pdf前端

        http://www.ibm.com/developerworks/cn/java/j-lo-javawebhiperf1/java

        http://www.ibm.com/developerworks/cn/java/j-lo-javawebhiperf2/        css3

 

        前面是读后感,下面是我针对最近几天学习到的提升Web性能进行了篇幅不小的总结,一来为新人提供帮助,二来本身作一下笔记,加深记忆。程序员

 

  •  性能以前端篇

--减小重绘web

        在HTML页面完成展示以后,动态改变页面元素或调整CSS样式都会引发浏览器重绘,性能的损耗直接取决于动态改变的范围:若是只是改变一个元素的颜色之类的信息则只会重绘该元素;而若是是增删节点或调整节点位置则会引发其兄弟节点也一并重绘。数组

        减小重绘并非说不要重绘,而是要注意重绘范围:①改动的DOM元素越深则影响越小,因此尽可能深刻节点改动;②对某些DOM样式有多重变更尽可能合并到一块儿修改。浏览器

 

以改变一个<a>标签的背景色、宽度和颜色为例。

 

Html代码   收藏代码
  1. <href="javascript:void(0);" id="example">传统的代码</a>   
  2. <script>   
  3.  var example = document.getElementById("example");   
  4.  example.ondblclick = function() {   
  5.  example.style.backgroundColor = "red";   
  6.  example.style.width = "200px";   
  7.  example.style.color = "white";   
  8.  }   
  9. </script>   

 以上会执行3次重绘,而经过CSS代替javascript屡次执行则只进行一次重绘。

 

 

Html代码   收藏代码
  1. <style>   
  2.  .dblClick {   
  3.  width: 200px;   
  4.  background: red;   
  5.  color: white;   
  6.  }   
  7. </style>   
  8. <href="javascript:;" id="example">CSS优化的代码</a>   
  9. <script>   
  10.  var example = document.getElementById("example");   
  11.  example.ondblclick = function() {   
  12.  example.className = "dblClick";   
  13.  }   
  14. </script>  

 

 

--避免脚本阻塞加载

        当浏览器在解析常规的script标签时,它须要等待script下载完毕,再解析执行,然后续的HTML代码只能等待。CSS文件引入要放在<head>头部,由于这是HTML渲染必备元素。为了不阻塞加载,应把脚本放到文档的末尾,而CSS是须要放在头部的!

 

Html代码   收藏代码
  1. <head>  
  2. <link rel="stylesheet" href="common.css">  
  3. ......  
  4. <script src="example.js"></script>  
  5. </body>  

 

 

--避免节点深层级嵌套

        深层级嵌套的节点在初始化构建时每每须要更多的内存占用,而且在遍历节点时也会更慢些,这与浏览器构建DOM文档的机制有关。浏览器会把整个HTML文档的结构存储为DOM“树”结构。当文档节点的嵌套层次越深,构建的DOM树层次也会越深。

 

以下代码,彻底可以去掉<div>或<span>其中一个标签。

 

Html代码   收藏代码
  1. <div>  
  2.   <span>  
  3.     <label>嵌套</label>  
  4.   </span>  
  5. </div>  

 

 

--页面缓存

        一般不设置缓存的状况下,每次刷新页面都会从新读取服务器的文件,而若是设置缓存以后,全部文件均可以从本地取得,这样明显极大提升了页面效率。

 

咱们能够经过设置页面头的expires来定义页面过时时间,将过时时间定久一点就达到了“永久”缓存。

 

Html代码   收藏代码
  1. <meta http-equiv="expires" content="Sunday 26 October 2099 01:00 GMT" />  

 固然,若是你的项目代码有变动,由于客户端缓存了文件就得不到最新的文件,势必形成显示错误。基于这个问题的解决方案就是给连接文件加一个时间戳,若是时间戳有变化,浏览器会认为是新文件,就会向服务器请求最新文件。

 

 

Html代码   收藏代码
  1. <script src="example2014-6-17.js"></script>  
  2. //若是是JSP,能够用EL表达式来取时间戳信息,这样管理更加方便  
  3. <script src="example${your time param}.js"></script>  
  4. //或者这样的写法更优秀:  
  5. <script src="example.js?time=2014-6-7"></script>  
  6. <script src="example.js?time=${your time param}"></script>  

 

 

--压缩合并文件

        全部涉及到请求数据的文件尽可能作压缩,好比Javascript文件、css文件及图片文件,特别是图片文件,若是没有高清晰要求,彻底能够压缩后再使用。

        数量少体积大的文件要比数量多体积小的文件加载速度快,因此有时候能够考虑将多个js文件、多个css文件合并在一块儿。

 

除此以外减小HTML文档大小还能够采起下面几种方法:

①删掉HTM文档对执行结果无影响的空格空行和注释

②避免Table布局

③使用HTML5

 

--HTML+CSS3+Javascript各司其职

        让三元素各司其职才能作出高性能的网页:HTML是页面之本也是内容之源,有了它就能跟CSS和Javascript交互;CSS3能够说是展示大师,并且日渐强大的CSS能代替Javascript作不少动态的事情如渐变、移动等动态效果;Javascript是动态数据之王,旧浏览器依靠js来完成动态效果展示,但如今的CSS也能完成js的工做,因此尽可能将工做交给css,这样会得到更好的性能。(这个说得有点大)

 

--图像合并实现CSS Sprites

        图像合并其实就是把网页中一些背景图片整合到一张图片文件中,再利用CSS 的“background-image”,“background- repeat”,“background-position”的组合进行背景定位,background-position能够用数字能精确的定位出背景图片的位置。

        一个页面要用到多个图标,彻底能够将多个图标合并成一个图,而后只须要发一次图片请求,经过css定位分割图标便可。

 

--避免使用Iframe

        使用iframe并不会增长同域名下的并行下载数,浏览器对同域名的链接老是共享浏览器级别的链接池,在页面加载过程当中iframe元素还会阻塞父文档onload事件的触发。而且iframe是html标签中最消耗资源的标签,它的开销比DIV、SCRIPT、STYLE等DOM高1~2个数量级。

 

避免onload事件被阻塞,可以使用JavaScript动态的加载iframe元素或动态设置iframe的src属性(但其仅在高级浏览器IE9及以上有效)。

 

Html代码   收藏代码
  1. <iframe id="if"></iframe>  
  2. document.getElementById("if").setAttribute("src","url");  

 

 

--多域名请求

        通常来讲,浏览器对于相同域名的图片,最多用2-4个线程并行下载(不一样浏览器的并发下载数是不一样的)。而相同域名的其余图片,则要等到其余图片下载完后才会开始下载。

        有时候,图片数据太多,一些公司的解决方法是将图片数据分到多个域名的服务器上,这在一方面是将服务器的请求压力分到多个硬件服务器上,另外一方面,是利用了浏览器的特性。(你们能够去新浪、腾讯门户网站查看,这些大型站点同一页面加载的图片可能由多个站点提供)

        注:一个HTML请求的域名也不要太多(2~3个差很少),多了可能形成不一样服务器链接时间差别,反而影响速度。

 

--避免空连接属性

        如<img src=""><a href="">这样的设置方式是很是不可取的,即便连接为空,在旧的浏览器也会以固定步骤发送请求信息。

        另外<a href="#"></a>也不可取,最好的方式是在连接中加一个空的js代码<a href="javascript:void();"></a>

 

--使用图像的BASE64编码

        base64是一串字符串,他能够表明一个图片的全部信息,也就是能够经过<img src="data:image/png;base64,S">(S表示一串base64码)来显示图片,这种方式不须要再向服务器发送请求,彻底由浏览器解析成图片。

        目前高级浏览器都支持此功能,但要注意两点:①低版本浏览器(如IE7)不支持;②base64字符串长度随图片的大小及复杂度成正比,base64也像URL同样,也有超出长度的状况(在IE8下很常见)。因此要根据状况来使用。

 

--显式设置图片的宽高

        若是HTML里的图片没有指定尺寸(宽和高),或者代码描述的尺寸与实际图片的尺寸不符时,浏览器则要在图片下载完成后再“回溯”该图片并从新显示,这会消耗额外时间。

<img src="demo.jpg" width="200" height="200">

 

--显式指定文档字符集

        若是浏览器不能获知页面的编码字符集,通常都会在执行脚本和渲染页面前,把字节流缓存,而后再搜索可进行解析的字符集,或以默认的字符集来解析页面代码,这会致使消耗没必要要的时间。

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

 

--渐进式加强设计

        渐进式加强设计的通俗解释就是:首先写一段知足全部浏览器的基本样式,再在后面针对不一样高级浏览器编写更漂亮的样式

        以下代码,全部浏览器都支持background-color: #2067f5;知足了浏览器基本现实需求,然后面的background-image: -webkit-gradient等则为不一样高级浏览器使用,只要浏览器识别就能执行这段代码(不识别,CSS也不会报错只会直接忽略)。

 

Html代码   收藏代码
  1. <div class="someClass"></div>   
  2. .someClass   
  3. { width: 100px;   
  4.  height: 100px;   
  5.  background-color: #2067f5;   
  6.  background-image: -webkit-gradient(linear, left top, left bottom, from(#2067f5),   
  7. to(#154096));   
  8.  background-image: -webkit-linear-gradient(top, #2067f5, #154096);   
  9.  background-image: -moz-linear-gradient(top, #2067f5, #154096);   
  10.  background-image: -ms-linear-gradient(top, #2067f5, #154096);   
  11.  background-image: -o-linear-gradient(top, #2067f5, #154096);   
  12.  background-image: linear-gradient(to bottom, #2067f5, #154096);   
  13. }  

参考阅读:多浏览器适配测试

 

 

--懒加载与预加载

        预加载和懒加载,是一种改善用户体验的策略,它实际上并不能提升程序性能,可是却能够明显改善用户体验或减轻服务器压力。

        预加载表示当前用户在请求到须要的数据以后,页面自动预加载下一次用户可能要看的数据,这样用户下一次操做的时候就马上呈现,依次类推。

        懒加载表示用户请求什么再显示什么,若是一个请求要响应的时间很是长,就不推荐懒加载。

 

--Flush机制

        当一个页面很是大,内容很是多,能够采用flush的形式分部分返回给页面,这样能告诉用户我正在工做,显示一部份内容比白屏等很长时间要好得多。在Java Web技术中,实现Flush很是简单,只要调用 HttpServletResponse.getWriter输出流的flush方法,就能够将已经完成加载的内容写回给客户端。

        这种方式只适用于返回数据特别多、请求时间特别长的状况,常规数据仍是用正常的实时所有返回最佳。这种实现方式实际会增长浏览器渲染时间和用户总体等待时间,但从用户体验上会更加优秀。

 

  • 性能之服务器优化

--CDN机制

        所谓的CDN,就是一种内容分发网络,它采用智能路由和流量管理技术,及时发现可以给访问者提供最快响应的加速节点,并将访问者的请求导向到该加速节点,由该加速节点提供内容服务。

        通俗点说,你在成都(浏览器)购买了北京卖家(服务器)的产品,北京卖家经过快递(CDN服务)寄送包裹,从北京到成均可以走路、坐汽车、火车或飞机,而采用CND的快递会选择飞机直达,由于这种寄送方式最快。

 

固然使用CDN有两个注意事项:

一、CDN加速服务很贵,若是你以为你的网站值得加速,能够选择购买;

二、CDN不适合局域性网站,好比你的网站只有某一个片区访问或者局域网访问,由于区域性网络原本就很近,无需CDN加速。

 

--HTTP协议的合理使用

        浏览器缓存带来的性能提高已经众人皆知了,而不少人却并不知道浏览器的缓存过时时间、缓存删除、什么页面能够缓存等,均可以由咱们程序员来控制,只要您熟悉HTTP协议,就能够轻松的控制浏览器。

 

扩展阅读:深刻理解HTTP协议

 

--动静分离

        所谓的动静分离,就是将Web应用程序中静态和动态的内容分别放在不一样的Web服务器上,有针对性的处理动态和静态内容,从而达到性能的提高。咱们知道若是一个HTML有多个域名请求数据文件会提升

Tomcat服务器在处理静态和并发问题上比较弱,因此事先动静分离的方式通常会用Apache+Tomcat、Nginx+Tomcat等。

        以Apache+Tomcat为例,其运行机理是:页面请求首先给Apache,而后Apache分析请求信息是静态仍是动态,静态则本机处理,动态则交给Tomcat作处理。

        这实际上是负载均衡的雏形,这样的实现不用让开发人员作任何特殊开发,一个<img src="demo.jpg">交给服务器便可,至于这个文件是从Apache仍是从Tomcat取得,开发人员彻底无需关注。

 

--HTTP持久链接

        持久链接(Keep-Alive)也叫作长链接,它是一种TCP的链接方式,链接会被浏览器和服务器所缓存,在下次链接同一服务器时,缓存的链接被从新使用。HTTP无状态性表示了它不属于长链接,但HTTP/1.1提供了对长链接的支持(不过这必须依赖浏览器和服务器双方均支持长链接功能才行),最多见的HTTP长链接例子是“断点下载”。

        浏览器在请求的头部添加 Connection:Keep-Alive,以此告诉服务器“我支持长链接,你支持的话就和我创建长链接吧”,而假若服务器的确支持长链接,那么就在响应头部添加“Connection:Keep-Alive”,从而告诉浏览器“个人确也支持,那咱们创建长链接吧”。服务器还能够经过Keep-Alive:timeout=..., max=...的头部告诉浏览器长链接失效时间。

        配置长链接一般是要服务器支持设置,有测试数据显示,使用长链接和不使用长链接的性能对比,对于Tomcat配置的maxKeepAliveRequests为50来讲,效率居然提高了将近5倍。

 

--GZIP压缩技术

        HTTP协议支持GZIP的压缩格式,当服务器返回的HTML信息报头中包含Content-Encoding:gzip,它就告诉浏览器,这个响应的返回数据已经压缩成GZIP格式,浏览器得到数据后要进行解压缩操做,必定程度上减轻了服务器传输数据的压力。

        不少服务器已经支持经过配置来自动将HTML信息压缩成GZIP,好比tomcat、又好比很火的Nginx。若是没法配置服务器级别的GZIP压缩机制,能够改成程序压缩。

 

Java代码   收藏代码
  1.  // 监视对 gzipCategory 文件夹的请求  
  2.  @WebFilter(urlPatterns = { "/gzipCategory/*" })   
  3.  public class GZIPFilter implements Filter {   
  4.   
  5.  @Override   
  6.  public void doFilter(ServletRequest request, ServletResponse response,   
  7.  FilterChain chain) throws IOException, ServletException {   
  8.  String parameter = request.getParameter("gzip");   
  9.  // 判断是否包含了 Accept-Encoding 请求头部  
  10.  HttpServletRequest s = (HttpServletRequest)request;   
  11.  String header = s.getHeader("Accept-Encoding");   
  12.  //"1".equals(parameter) 只是为了控制,若是传入 gzip=1,才执行压缩,目的是测试用  
  13.  if ("1".equals(parameter) && header != null && header.toLowerCase().contains("gzip")) {   
  14.  HttpServletResponse resp = (HttpServletResponse) response;   
  15.  final ByteArrayOutputStream buffer = new ByteArrayOutputStream();   
  16.   
  17.  HttpServletResponseWrapper hsrw = new HttpServletResponseWrapper(   
  18.  resp) {   
  19.   
  20.  @Override   
  21.  public PrintWriter getWriter() throws IOException {   
  22.  return new PrintWriter(new OutputStreamWriter(buffer,   
  23.  getCharacterEncoding()));   
  24.  }   
  25.   
  26.  @Override   
  27.  public ServletOutputStream getOutputStream() throws IOException {   
  28.  return new ServletOutputStream() {   
  29.   
  30.  @Override   
  31.  public void write(int b) throws IOException {   
  32.  buffer.write(b);   
  33.  }   
  34.  };   
  35.  }   
  36.   
  37.  };   
  38.   
  39.  chain.doFilter(request, hsrw);   
  40.  byte[] gzipData = gzip(buffer.toByteArray());   
  41.  resp.addHeader("Content-Encoding", "gzip");   
  42.  resp.setContentLength(gzipData.length);   
  43.  ServletOutputStream output = response.getOutputStream();   
  44.  output.write(gzipData);   
  45.  output.flush();   
  46.  } else {   
  47.  chain.doFilter(request, response);   
  48.  }   
  49.  }   
  50.  // 用 GZIP 压缩字节数组  
  51.  private byte[] gzip(byte[] data) {   
  52.  ByteArrayOutputStream byteOutput = new ByteArrayOutputStream(10240);   
  53.  GZIPOutputStream output = null;   
  54.  try {   
  55.  output = new GZIPOutputStream(byteOutput);   
  56.  output.write(data);   
  57.  } catch (IOException e) {   
  58.  } finally {   
  59.  try {   
  60.  output.close();   
  61.  } catch (IOException e) {   
  62.  }   
  63.  }   
  64.  return byteOutput.toByteArray();   
  65.  }   
  66. ……  
  67.  }  

 

 

  • 总结

        细节决定成败,系统慢是由一个又一个不良的小细节形成的,因此开发初期作好充足的准备,开发中认真负责、不偷工减料,维护期更要注重代码质量,这样才能让咱们的系统稳定高效。

        我的以为一个产品的新版本质量能够从核心js文件看出来:若是核心js文件大小比上一版本大太多,明显在性能上就会有问题,咱们要争作像谷歌、亚马逊这样优秀的团队--可以在功能升级的同时减少核心js文件大小。

相关文章
相关标签/搜索