`
zhengyun_ustc
  • 浏览: 83074 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

前端工程打开速度优化的循序渐进总结

阅读更多
创建人:@郑昀
更新日期:2013年5月8日 分类: 前端技术
 
优化的重要指标:
  • 页面打开速度(Fully Loaded)
    • 网站首页(或列表页)之 First View :打开速度应在 3秒+0.5秒 内;
    • 对 Repeat View 时的各项指标暂不作要求;
  • 首屏打开时间(Start Render)
    • 网站首页(或列表页) 之 First View :首屏渲染速度应在 1秒+0.5秒 内;
  • 文档解析完毕时间(Document Complete):
    • 对此指标暂不作要求。
指标测试方法参考附录A。
提纲:
  1. 遵循常规优化建议
  2. 外联内联js/css的位置摆放建议
  3. combo handler的引入
  4. 图片无损压缩的优化
  5. 减少 dom elements 的数量
  6. 引入 textarea/script 元素做延迟解析异步渲染

优化第一阶段:遵循常规优化建议
本阶段所使用工具参考附录B。
常规优化建议:
  1. javascript 外联文件引用放在 html 文档底部:具体如何摆放内联JS/CSS和外联JS/CSS,请参考 优化第二阶段;
  2. css 外联文件引用在 html 文档头部:位于 header 内;
  3. http 静态资源尽量用多个子域名:充分利用现代浏览器的多线程并发下载能力。浏览器的多线程下载能力,参考 附录C;
  • 具体建议:
    • JS、CSS、CSS背景图片、CSSSprite图片分散在 s0~s2.55tuanimg.com 下;
    • 业务类图片分散在 p0~p3.55tuanimg.com 下;
  • 服务器端提供 html 文档和 http 静态资源时,尽量开启 gzip 压缩
    • json/xml 等格式的文本响应,也建议开启 gzip ;
    • jepg/png 等图片,可以选择不开启 gzip,因为可能服务器端图片无损压缩算法已经很强悍了,不需要依赖于 gzip;
  • 在 js、css、image 等资源响应的 http headers 里,设置 expires、last-modified
    • 含义参考 附录D;
    • 郑昀实例示范:
    • Nginx设置示范:
      • location ~ .*\.(js|css)${

        expires 30d;

        }

        location ~ .*\.(gif|jpg|jpeg|png|bmp)${

        expires 1M;

        }

  • 尽量减少 HTTP Requests 的数量
    • 通过 combo handler 合并 js 和 css 的下载,参考 优化第三阶段;
    • 本阶段请尽量减少外联 js/css 文件数,尽量减少 ajax 调用;
  • js/css 的 minify:可统一通过 combo handler 做到压缩加合并;
  • 减少不必要的 301/302 跳转:别让页面打开时间浪费在302多次跳转上(每次可能几十毫秒);
  • 大量使用 CSS Sprites:这样做可以大大地减少CSS背景图片的HTTP请求次数;
  • 首屏不需要展示的较大尺寸图片,请使用 LazyLoad 
  • 避免404错误:请求一个外联 js 失败时获得的404错误,不但会堵塞并行的下载,而且浏览器会尝试分析404响应的内容,来辨识它是否是有用的Javascript代码;
  • 减少 cookies 的大小:尽量减少 cookies 的体积对减少用户获得响应的时间十分重要;
    • 去除不必要的 cookie ;
    • 尽量减少 cookie 的大小;
    • 留心将 cookie 设置在适当的域名下,避免影响到其他网站;
    • 设置适当的过期时间。一个较早的过期时间或者不设置过期时间会更快地删除 cookie,从而减少响应时间。
  • 使用无 cookies 的域
    • 当浏览其请求一个静态图片并一同发送 cookie 时,服务器并不需要这些 cookies 。这样只是毫无益处地创建了多余的网络流量。应当保证静态资源在请求时没有携带 cookies,所以需要把你的静态资源放在另一个子域名下。
    • 如果你的域名是 www.example.org,你可以将你的静态资源放在 static.example.org 中。如果你把 cookie 设置在顶级域名 example.org 上而不是 www.example.org,那么所有发送至 static.example.org 的请求会包括那些 cookies。在 这种情况下,你可以用一个全新的没有 cookie 的域名来放置你的静态资源。
  • 避免使用 javascript 来定位布局

  •  
    优化第二阶段:外联内联js/css的位置摆放建议
    玉伯定义的加载和阻塞三定律如下:
    • 定律一:资源是否下载依赖 JS 执行结果——JS 有可能会修改 DOM。典型的,可能会有 document.write。这意味着,在当前 JS 加载和执行完成前,后续所有资源的下载有可能是没必要的。这是 JS 阻塞后续资源下载的根本原因。
    • 定律二:JS 执行依赖 CSS 最新渲染——JS 的执行有可能依赖最新样式。比如,可能会有 var width = $('#id').width(). 这意味着,JS 代码在执行前,浏览器必须保证在此 JS 之前的所有 css(无论外链还是内嵌)都已下载和解析完成。这是 CSS 阻塞后续 JS 执行的根本原因。
    • 定律三:现代浏览器存在 prefetch 优化—— 现 代浏览器在竞争中,在 UI update 线程之外,还会开启另一个线程,对后续 JS 和 CSS 提前下载(注意,仅提前下载,并不执行)。有了 prefetch 优化,这意味着,在不存在任何阻塞的情况下,理论上 JS 和 CSS 的下载时机都非常优先,和位置无关。
    根据三定律,郑昀认为:

    一,如果真的需要把外联jscss放在head里,那也需要从下面这种排序

    1.         外联js

    2.         外联css

    3.         外联js

    统一为:

    1.         外联css

    2.         外联js

    3.         外联js

    不要scriptcss交替混编。

     

    原因是,据有人称:『

    Firefox 4+开始,对prefetch的策略有些许调整,调整在于 head  css  js 的位置。

    css 在外联 js 后面时,可能会在 script 后面的 css 加载好之前,提前进行首次渲染。

    然后等后面的 css 加载好后,再次更新 Render Tree 并进行渲染,造成页面闪烁现象。

    即,各种优化策略,似乎随着浏览器版本不同,头可能发生细微差异。

    所以郑昀认为,保守做法是,js 和 css 不要在 head 里交替混编,统一为先外联css再外联js

     

    二,但只有万不得已时,才会在 head 里放外联js,否则请把外联js放置到</body>前。

    原因是张克军的《js和css的顺序关系》指出:

        只要 head 里出现外联js,无论如何放,css文件都不能和body里的请求并行。
        body 里 dom 渲染取决于 head 里的js执行完

    外联js放在页面最后,高级浏览器会自动做优化(prefetch),你不用担心,它也可能会提前下载。

     


     
    优化第三阶段:combo handler 的引入
    背景
    Combo Handler 是 Yahoo! 开发的一个 Apache 模块,它实现了开发人员简单方便地通过URL来合并JavaScript和CSS文件,从而大大减少文件请求数。
    目的
    它满足 Yahoo! 前端优化第一条原则:Minimize HTTP Requests,来减少三路握手和HTTP请求的发送次数。
    国内实例
    淘宝网首页meta里多个js合并的声明:
    <script src="http://a.tbcdn.cn/??s/kissy/1.2.0/kissy-min.js,p/global/1.0/global-min.js,p/fp/2012/core.js,p/fp/2012/fp/module.js,p/fp/2012/fp/util.js,p/fp/2012/fp/directpromo.js?t=2012062320120712.js" data-fp-timestamp="20120703"></script>
    js之间用英文逗号或&符号分隔。此src的Response是多个js文件的内容拼装。
    国内的 Combo Script 支持
    淘宝李晶-拔赤在 https://github.com/jayli/combo 下发布了combo.php和minfy.php,能够做到合并文件(不压缩),以及合并且压缩。
    文件列表:
     - combo.php 合并文件,不压缩
     - minify.php 合并压缩文件
     - cssmin.php 压缩css
     - jsmin.php 压缩js
     - cb.php 淘宝CDN合并文件策略的模拟
    脚本使用:
     - 要求php5及以上版本
     - 程序在找不到本地文件的情况下,会去指定的cdn上找同名文件
     - 程序会自动转义-min文件为源文件,因此要约定-min文件和原文件要成对出现
     - 需要定义combo.php和minify.php中的$YOUR_CDN变量
     - 如果只是合并压缩local文件,则不必重置$YOUR_CDN变量
     - 这里提供cb.php,用来实现tbcdn的开发环境的模拟,apache的配置在cb.php中
    CDN上的 Combo Handler支持
    1)2008年7月YUI Team宣布在YAHOO! CDN上对YUI JavaScript组件提供Combo Handler服务
    2)淘宝CDN支持Combo Handler,用逗号分隔js/css,用两个问号来触发combo特性:
     - http://a.tbcdn.cn/??1.js,2.js
     - http://a.tbcdn.cn/subdir/??1/js,2.js
    用一个问号来添加时间戳,如:
    - http://a.tbcdn.cn/??fp/directpromo.js?t=2012062320120712
     
    为了避免 CDN 缓存错误的版本,combo上线的访问策略是:
    1)静态文件传到服务器端;
    2)部署人员使用线上静态文件服务器的IP地址直接请求combo服务,挨个儿combo请求一次;
    3)部署人员确认上面的请求都成功、内容无误后,再换成CDN地址再次请求,确保CDN缓存正确的文件内容。
     

     
    优化第四阶段:图片无损压缩的优化
    页面上的各种图片是否有优化的余地,推荐使用 PageSpeed 检测一下。
    下面的建议来自于冯凯。
    由于专卖店等各种业务上传的图片有 jpeg、png 和 gif 等格式,因此三种格式都需要优化:
    1)jpegtran和jpegoptim的压缩效果几乎完全相同。
    但jpegtran有progressive编码(渐进式的展示,先显示模糊的,再逐步清晰),而且通常(84%的概率)对于大图片(10k+)压缩比更高。
    虽然我们的大部分页面已经改成延迟加载了,但对于非延迟加载的页面,效果明显更好。
    经测试,pagespeed 并没有按照 progressive 方式提供建议。
     
    2)测试了png的几种压缩方式,压缩效果各异。测试的一张图片 optipng 只压缩了约5%,但其他几种达到了20%+
    经测试,pagespeed上给出的可压缩比例是按照optipng给出的。
    pngout据说采用了不同的编码,因此对小图片压缩效果更好。用imageoptim测试确实略优,但命令行上还没找到合适的调用参数。
    目前决定采用pngcrush。
    对于采用png8,以大幅压缩的方法,我们不做技术处理。
     
    3)gif就采用gifsicle做压缩。
    大部分情况下,我们不建议采用gif图片。对于单帧gif更应该用png格式替代。
    这里我们暂不考虑通过技术处理来吧单帧gif转换成png。
     
    4)采用php的exec调用shell脚本的方式来执行这些bin文件。
     
    参考资料:
     

     
    优化第五阶段:减少 DOM Elements 的数量
    玉伯说,对于典型的淘宝商品详情页,经测试发现,每增加一个 DOM 节点,会导致首屏渲染时间延迟约 0.5ms
    2011年时,我们首页一个商品节点包含了21个DOM节点,充满了大量的em、strong、span。
    所以前端开发部门必须与产品部交互设计人员积极沟通,而不仅仅是在她们提供的交互设计稿件上切图,必须在简化视觉元素和精简DOM节点上表达自己的意见。
    2012年,简化设计后,首页一个商品节点包含13个节点。
     

     
    优化第六阶段:引入 textarea/script 元素做延迟解析异步渲染
    textarea 延迟渲染原理
    玉伯介绍,HTML 元素中有一种 RCDATA elements,含 textarea 和 title 。
    RCDATA指的是,Replaceable Character Data。
    如果用隐藏的 textarea 来存放 html 代码,textarea 中的内容会按照 RCDATA 规则来解析:
    1. 遇到 & 时,会尽可能得到实体字符。
    2. 遇到 </textarea(\s|\\|>) 时,会结束解析。
    3. 其他都直接作为 textarea 的内容。
    http://images.cnblogs.com/cnblogs_com/zhengyun_ustc/255879/o_clipboard03.png
    获取也非常简单:
    http://images.cnblogs.com/cnblogs_com/zhengyun_ustc/255879/o_clipboard04.png
    yiminghe介绍对 于屏幕外延迟渲染的 html 存放在隐藏(visibility:hidden)的 textarea 中,并且该 textarea 占据本该渲染的位置,监控窗体滚动,当textarea进入可见区域,将该 textarea 内的 value, 插入到 textarea 之前,并删除掉 textarea 
     
    这样,把大量不需要在首屏展示的html代码分模块放入一个一个的 textarea 里,大大减少了DOM节点数,从而给浏览器合理的喘息(UI Update)时间,等首屏真正在显示器上绘制出来后,再得到 textarea.value ,填充回 DOM Tree。
     
    textarea+datalazyload,相对于其他延迟加载异步渲染解决方案,最大好处,还是减少首屏绘制时的DOM节点总数。
     
    参考资料:
    script 延迟渲染原理 
    与前面说的 textarea 存放 html 代码一样,你也可以用 script 来存放,目的都是减少 DOM 节点数。
    浏览器在拿到 html 代码时,首次 Tokenization — Tree Construction 的速度就会大大加快。
    http://images.cnblogs.com/cnblogs_com/zhengyun_ustc/255879/o_clipboard026.png
     
    某网是怎么实践的
    在某网商品详情页上,HTML 文档底部遍布着这样的代码:
    http://images.cnblogs.com/cnblogs_com/zhengyun_ustc/255879/o_clipboard027.png
    注意这些 script 的 type 是 text/x-template ,这是YUI类库自己定义的元素type。
    你可以注意到,LABjs 也玩过这个小技巧,也是自己定义了一个元素 type“text/cache”, 由于浏览器不认识这种 type,就会主动忽略这个 HTML元素。
     
    什么时候取出这些隐藏HTML代码呢?
    那就要用到这些 script 的 id 了。
    YUI的教程上是这么获得 HTML 代码:
        template: Y.one('#todo-item-template').getHTML(),
    某网的做法是:
    http://images.cnblogs.com/cnblogs_com/zhengyun_ustc/255879/o_clipboard028.png
    http://images.cnblogs.com/cnblogs_com/zhengyun_ustc/255879/o_clipboard029.png
    某网由于走的是 YUI3.0 体系,所以可以利用 script 存放html代码技巧,让商品详情页首屏更快地渲染出来。
     
    我们的实践
    在商品详情页上,我们把很多不需要首屏渲染的 html 代码放入了类似于
    <textarea id="goodsAll_info"  style="display:none;"></textarea>
    的隐藏 textarea 里了。
    然后在 html 文档底部,放内联 js 来读取:
    <script type="text/javascript">
    $(function(){
    var area = document.getElementById("goodsAll_info").value;
    document.getElementById("goodsAll_info_div").innerHTML = area;
    });
    </script> 
     
     

     
    附录A:页面打开速度和首屏打开时间的测量
    推荐工具:
    1. 推荐使用 http://www.webpagetest.org/ 评测,由于它受限于并发测试和带宽,所以资源下载速度较差,只能作为与竞争对手对比测试的依据;
    • Test Location 请选择亚洲的中国江苏节点;
    • Browser 请选择 Firefox、IE9、Chrome等现代浏览器;
    • 如下图所示:
    • 郑昀
  • 运维部的每周博睿检测数据报告,我们以博睿的数据为准
    • 博睿从它的各地监测节点以及不同电信链路访问,得到一个响应速度的平均值;
  • Google PageSpeed https://developers.google.com/speed/pagespeed/insights 的 Critical Path Explorer;
  • 附录B:能提出常规优化建议的工具
    推荐工具:
    1. Firefox插件 YSlow! ;
    2. Google PageSpeed https://developers.google.com/speed/pagespeed/insights ;
    附录C:浏览器多线程下载能力一览
    参考怪飞的文章《各浏览器的并行连接数(同域名) 》:
    Browser HTTP/1.1 HTTP/1.0
    IE 6,7 2 4
    IE 8 6 6
    Firefox 3+ 6 6
    Safari 3+ 4 4
    Chrome 3+ 4 4
    Chrome 11+ 6
    Opera 10+ 4 4
    Opera 11+ 16
    附录D:expires和last-modified概念
    1)Expires
    给出的日期/时间后,被响应认为是过时。如Expires: Thu, 02 Apr 2009 05:14:08 GMT
    需和Last-Modified结合使用。用于控制请求文件的有效时间,当请求数据在有效期内时客户端浏览器从缓存请求数据而不是服务器端. 当缓存中数据失效或过期,才决定从服务器更新数据。
    2)Last-Modified和Expires
    Last-Modified标识能够节省一点带宽,但是还是逃不掉发一个HTTP请求出去,而且要和Expires一起用。而Expires标 识却使得浏览器干脆连HTTP请求都不用发,比如当用户F5或者点击Refresh按钮的时候就算对于有Expires的URI,一样也会发一个HTTP 请求出去,所以,Last-Modified还是要用的,而 且要和Expires一起用。
     

    赠图一枚:
    @正和岛标准 :【看图】做事感觉特别困难的时候,可能收获也会特别巨大。
     
    @烈火在线:每次看产品经理发来的文档,都是这种感觉。。。
    分享到:
    评论

    相关推荐

      《循序渐进Vue.js3前端开发实战》实战范例.zip

      总的来说,前端开发是一个不断发展与进步的领域,随着新的样式解决方案和组件库的不断涌现,以及前端框架的不断更新和演进,前端开发的技术栈和工具链也在不断完善和丰富。未来,前端社区将继续充满朝气与活力,为...

      Vue.js前端开发 PDF

      Vue.js是目前非常流行的前端开发框架之一,被誉为前端三大框架之一,另外两个是React和Angular。Vue.js的设计理念是简洁、易用且高效,它旨在通过最小的学习曲线提供强大的功能,使得开发者能够快速构建交互式的用户...

      循序渐进的javascript范例资料

      这份“循序渐进的JavaScript范例资料”旨在帮助初学者和有经验的开发者逐步掌握JavaScript的核心概念和技术。 首先,我们要了解JavaScript的基础。JavaScript是一种解释型、弱类型、基于原型的动态语言。它在浏览器...

      【JavaScript源代码】浅谈如何循序渐进的学好JS.docx

      以下是一些循序渐进学好JavaScript的方法: 1. **清楚JS的定位**:理解JavaScript作为客户端脚本语言的角色,主要任务是处理用户交互、更新页面内容、进行异步通信(Ajax)等。始终围绕这个核心思想去学习,有助于...

      vue最新实战项目教程,从零开始,一步一个脚印,循序渐进 跟着我一起学习vue吧!.zip

      vue-todos预览地址(响应式设计,pc端,移动端) 初始化地址...让vue.js的初学者循序渐进的,有效的学习vuejs 。運行# 更新依赖包npm install# 本地运行 at localhost:8080npm run dev# 打包npm run build你学习到vue-cli

      WEB前端工程师Web前端性能优化经验分享

      最后,使用JSON进行数据交换是前端优化的另一个重要方面。JSON是一种轻量级、语言无关的数据交换格式,与XML相比,其数据量更小,解析更快。由于JSON天然就与JavaScript兼容,使得数据操作更加直观和高效。JSON数据...

      前端工程化 体系设计与实践 高清完整版

      适读人群 :本书适合对前端工程化有一定理解和实践的中高级前端工程师阅读,同样适合对前端工程化感兴趣的服务器端开发者以及运维人员阅读。 1.本书由周爱民老师倾情作序,美团技术总监赵强、搜狐高级技术经理邵充、...

      前端工程化技术架构.pdf

      “阿基里斯之踵”是前端工程化的痛点之处,即开发速度慢、协同效率低、距离业务逻辑较远、用户体验较近等问题。 解决思路: 1. 云+端一体化:前端工程化技术架构的目标是将前端开发流程自动化、标准化,以提高开发...

      web 前端年总结ppt模板

      Web 前端年总结 PPT 模板知识点总结 从提供的文件信息中,我们可以总结出以下几个知识点: 1. web 前端技术研发部工作总结的重要性 通过文件的标题和描述,我们可以了解到 web 前端技术研发部的工作总结对于公司...

      前端工程化 体系设计与实践

      在现代Web开发中,前端工程化...总结,前端工程化体系设计与实践是前端开发者必须掌握的核心技能之一。通过合理的架构设计、工具选择和最佳实践,可以打造出高效、稳定、易维护的前端项目,适应快速变化的Web开发环境。

      vue最新实战项目教程,从零开始,一步一个脚印,循序渐进

      vue-cli 开发环境的搭建 分析api文档,组件化编程 vue基础( 1.实例 2.组件 3.指令 4.选项 5.模板渲染 6....vue进阶(1.vue生命周期 2.vuex使用 3.axios的使用 4.mock.js 前端模拟数据) 跨域问题的解决办法

      web前端笔试题面试题汇总+前端优化总结

      "前端笔试题面试题汇总+前端优化总结" 前端优化的目的是什么?从用户角度而言,优化能够让页面加载得更快、对用户的操作响应得更及时,能够给用户提供更为友好的体验。从服务商角度而言,优化能够减少页面请求数、...

      网易高级前端工程师跟着他每周重点攻克一个前端面试重难点

      总的来说,"网易高级前端工程师跟着他每周重点攻克一个前端面试重难点"的学习计划涵盖了JavaScript核心、前端框架、性能优化、工程化实践、浏览器原理以及安全等多个方面。通过系统学习和实践,你将在前端开发的道路...

      1让你页面速度飞起来,Web前端性能优化。.txt

      让你页面速度飞起来,Web前端性能优化。 让你页面速度飞起来,Web前端性能优化。百度云盘视频资料,下载直接看

      让你页面速度飞起来 Web前端性能优化(视频教程+ppt)

      ### Web前端性能优化知识点 #### 一、构建优化 **1.1 文件压缩与合并** - **文件压缩**:利用工具如UglifyJS...总之,Web前端性能优化是一个系统性的工程,需要开发人员具备全面的知识体系和实践经验才能有效实施。

      web前端性能优化

      针对web前端性能低下的问题,王成、李少元、郑黎晓、缑锦、曾梅琴、刘慧敏等学者系统地提出了一套旨在提高网页加载速度、呈现速度和用户体验的完整Web前端性能优化解决方案。该方案涵盖了服务器端优化、HTML优化、...

      前端JS打开CMD执行程序 不限制浏览器 JS打开浏览器 谷歌浏览器前端打开其他程序 谷歌浏览器JS打开其他程序

      前端JS打开CMD执行程序 不限制浏览器 JS打开浏览器 谷歌浏览器前端打开其他程序 谷歌浏览器JS打开其他程序

      前端开发经验沉淀 前端性能优化及开发工具 共25页.ppt

      前端性能优化是指在前端开发过程中,对Web应用程序的性能进行优化,以提高用户体验和页面加载速度。本文将介绍前端性能优化的经验沉淀,包括机票双程性能优化和开发工具的使用。 一、前端性能优化 1. 机票双程性能...

    Global site tag (gtag.js) - Google Analytics