一:web前端页面优化:
1.web页面的具体是什么?前身?
web前端页面作为呈现给用户看的页面,也就是浏览器可以解析出资源的通过一定程序而出现的页面,对于可以开发人员,很好懂:就是**HTML(Hyper Text Markup Language【超文本标记语言】)+CSS(Cascading Style Sheets【表现HTML(标准通用标记语言的一个应用)或XML(标准通用标记语言的一个子集)等文件样式的计算机语言】)+JS(javascript【一种由Netscape的LiveScript发展而来的脚本语言,主要目的是为了解决服务器终端语言遗留的速度问题】)**。
Web前端作为开发团队中不可或缺的一部分,需要按照相关规定进行合理编写(一部分不良习惯可能给自己和他人造成不必要的麻烦)。不同公司不同团队具有不同的规范和文档
A.**基本原则**
符合web标准(UTF-8,HTML5),语义化html(HTML5新增要求,减少div和span等无特定语义的标签使用),结构表现行为分离(HTML-CSS-JS代码分离,不同行为代码高内聚低耦合),兼容性优良(早期版本浏览器兼容,移动端和PC端设备兼容).页面性能方面(减少请求次数,例如使用精灵图和sass语法),代码要求简洁明了有序,尽可能的减小服务器负载,保证最快的解析速度(减小repaint和reflow)
B.**文件命名规范**
1、**html,css,js,lib,images文件均存放至项目的目录中**。如果使用相关前端框架,根据框架的文件格式进行合理布局。
2、所有文件夹及文件使用英文命名(避免使用中文路径)。
3、**html文件**:入口文件使用index.html。如果有对应的设计组设计原稿,需要将对应的设计稿和html文件命名一致并合理存放。
4、**css文件命名**:后缀.css。通用initial.css,初始化base.css,首页index.css,其他页面按照对应的html命名。
5、**Js文件命名**:英文命名,后缀.js.通用common.js,初始化base.js。 其他页面按照对应的html命名。
C.**HTML规范**
1、**文档类型声明及编码:统一为html5声明类型**。书写时利用IDE实现层次分明的缩进(默认缩进4空格)。
2、**非特殊情况下CSS文件放在body部分<meta>标签后**。非特殊情况下大部分JS文件放在<body>标签尾部(如果需要界面未加载前执行的代码可以放在head标签后)避免行内JS和CSS代码。
3、**所有编码需要遵循html(XML)标准**,标签&属性&属性命名必须由小写字母及下划线数字组成,且所有标签必须闭合,包括br(),hr()等。属性值用双引号。
4、**引入JS库文件,文件名须包含库名称及版本号及是否为压缩版**,比如jquery-1.4.1.min.js。引入插件,文件名格式为库名称+插件名称,比如jQuery.bootstrap.js。
5、**书写页面过程中,请考虑向后扩展性**。class&id参见css书写规范.
6、**需要为html元素添加自定义属性**的时候,首先要考虑下有没有默认的已有的合适标签去设置,如果没有,可以使用须以"data-"为前缀来添加自定义属性,避免使用"data:"等其他命名方式。
7、**语义化html**,如标题根据重要性用h*(同一页面只能有一个h1),段落标记用p,列表用ul,内联元素中不可嵌套块级元素。
8、**尽可能减少div多层级嵌套**。
9、**书写链接地址时,必须避免重定向,**例如:href="http://myVue.com/",即须在URL地址后面加上“/”;
10、**在页面中尽量避免使用style属性**,即style="…"。
11、**必须为含有描述性表单元素**(input,textarea)添加label,如姓名:须写成:姓名:
12、**能以背景形式呈现的图片,尽量写入css样式中**。
13、**重要图片必须加上alt属性**。给重要的元素和截断的元素加上title。
14、**给区块代码及重要功能(比如循环)加上注释**,方便后台添加功能。
15、**特殊符号使用**:尽可能使用代码替代:比如<(<)&>(>)&空格()&»(»)等等。
D.**CSS规范**
1、**编码规范为utf-8。**
2、**协作开发及分工**:i会根据各个模块,同时根据页面相似程序,事先写**体框架文件,分配给前端人员实现内部结构&表现&行为。共用css文件base.css由i书写,协作开发过程中,每个页面请务必都要引入,此文件包含reset及头部底部样式,此文件不可随意修改。
3、**class与id的使用**:id是唯一的并是父级的,class是可以重复的并是子级的,所以id仅使用在大的模块上,class可用在重复使用率高及子级中。id原则上都是由我分发框架文件时命名的,为JS预留钩子的除外。
4、**为JS预留钩子的命名**,请以js_起始,比如:js_hide,js_show。
5、**class与id命名**:大的框架命名比如header/footer/wrapper/left/right之类的在2中由i统一命名.其他样式名称由小写英文&数字&来组合命名,如i_comment,fontred,width200。避免使用中文拼音,尽量使用简易的单词组合。总之,命名要语义化,简明化
6、**规避class与id命名**(此条重要,若有不明白请及时与i沟通):a)通过从属写法规避,示例见d。b)取父级元素id/class命名部分命名,示例见d。c)重复使用率高的命名,请以自己代号加下划线起始,比如i_clear。d)a,b两条,适用于在2中已建好框架的页面,如,要在2中已建好框架的页面代码中加入新的div元素,按a命名法则:...,样式写法:#mainnav.firstnav{.......}按b命名法则:...,样式写法:.main_firstnav{.......}
7、**css属性书写顺序**,建议遵循:布局定位属性-->自身属性-->文本属性-->其他属性.此条可根据自身习惯书写,但尽量保证同类属性写在一起.属性列举:布局定位属性主要包括:display&list-style&position(相应的top,right,bottom,left)&float&clear&visibility&overflow;
**
**自身属性主要包括:****width&height&margin&padding&border&background。
**文本属性主要包括**:color&font&text-decoration&text-align&vertical-align&white-space&
其他&content。
8、**书写代码前,提高样式重复使用率。**
9、**充分利用html自身属性及样式继承原理减少代码量**,例如:
即可实现日期居右显示
![](https://i.imgur.com/8ST0oN4.jpg)
10、**样式表中中文字体名**,请务必转码成unicode码,以避免编码错误时乱码。
11、**背景图片请尽可能使用精灵图技术**,减小http请求,考虑到多人协作开发,精灵图按模块制作。
12、**使用table标签时**(尽量避免使用table标签),请不要用width/height/cellspacing/cellpadding等table属性直接定义表现,应尽可能的利用table自身私有属性分离结构与表现,如thead,tr,th,td,tbody,tfoot,colgroup,scope。(cellspaing及cellpadding的css控制方法:table{border:0。margin:0。border-collapse:collapse。}tableth,tabletd{padding:0。},base.css文件中我会初始化表格样式)
13、**杜绝使用兼容ie8。**
14、**用png图片做图片时,要求图片格式为png-8格式**,若png-8实在影响图片质量或其中有半透明效果,请为ie6单独定义背景:_background:none。_filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=crop,src=’img/bg.png’)。
15、**避免兼容性属性的使用**,比如text-shadow||css3的相关属性。
16、**减少使用影响性能的属性,**比如position:absolute||float。
17、**必须为大区块样式添加注释,小区块适量注释。**
18、**代码缩进与格式**:建议单行书写,可根据自身习惯,后期优化会统一处理。
E. **JS书写规范**
1、**文件编码统一为utf-8,**书写过程过,每行代码结束必须有分号。原则上所有功能均根据XXX项目需求原生开发,以避免网上down下来的代码造成的代码污染(沉冗代码||与现有代码冲突||...)。
2、**库引入**:原则上仅引入jQuery库,若需引入第三方库,须与团队其他人员讨论决定。
3、**变量命名**:驼峰式命名.原生JS变量要求是纯英文字母,首字母须小写,如myVue。jQuery变量要求首字符为'_',其他与原生JS规则相同,如:_myVue。另,要求变量集中声明,避免全局变量.
4、**类命名**:首字母大写,驼峰式命名.如MyVue。
5、**函数命名**:首字母小写驼峰式命名.如myVue()。
6、**命名语义化**,尽可能利用英文单词或其缩写。
7、**尽量避免使用存在兼容性及消耗资源的方法或属性**,比如eval_r()&innerText。
8、**后期优化中,JS非注释类中文字符须转换成unicode编码使用,以避免编码错误时乱码显示。**
9、**代码结构明了,加适量注释.提高函数重用率。**
10、**注重与html分离,减小reflow,注重浏览器性能**.
F.**图片规范**
1、**所有页面元素类图片均放入img文件夹**,测试用图片放于demo文件夹。
2、**图片格式gif/png/jpg。提倡使用webp文件格式**,使用软件进行图片压缩。
3、**命名全部用小写英文字母||数字||_的组合,**其中不得包含汉字||空格||特殊字符;尽量用易懂的词汇,便于团队其他成员理解。另,命名分头尾两部分,用下划线隔开,比如ad_left01.gif||btn_submit.gif。
4、**在保证视觉效果的情况下选择最小的图片格式与图片质量,以减少加载时间**。
5、**尽量避免使用半透明的png图片**(若使用,请参考css规范相关说明)。
6、**运用css精灵图技术集中小的背景图或图标**,减小页面http请求,但注意,请务必在对应的精灵图psd源图中划参考线,并保存至img目录下
G.**测试规范**
开发及测试工具约定建议使用Aptana-Sublime-Vim-WebStrom,亦可根据自己喜好选择,但须遵循如下原则:
1、**不可利用IDE的视图模式'画'代码。**
2、**不可利用IDE生成相关功能代码。**
3、**编码必须格式化,比如缩进**。测试工具:前期开发仅测试FireFox&IE6&IE7&IE8,后期优化时加入Opera&Chrome&Safari。建议测试顺序:FireFox-->IE-->Opera-->Chrome-->Safari。
2.**为什么要做性能优化?**
网站前端的用户体验决定了用户是否想要去使用网站的功能,而网站的功能决定了用户是否会一票否决前端体验。 不仅仅如此,如果前端优化得好,他不仅可以为企业节约成本,他还能给用户带来更多的用户,因为增强的用户体验。总结成三点就是:
(1)、**加快页面展示和运行速度**
(2)、**节约服务器带宽流量**
(3)、**减少服务器压力**
**3.Web页面的性能**
我们每天都会浏览很多的Web页面,使用很多基于Web的应用。这些站点看起来既不一样,用途也都各有不同,有在线视频,Social Media,新闻,邮件客户端,在线存储,甚至图形编辑,地理信息系统等等。虽然有着各种各样的不同,但是相同的是,他们背后的工作原理都是一样的:
**用户输入网址**
**浏览器加载HTML/CSS/JS,图片资源等**
**
**浏览器将结果绘制成图形****
**用户通过鼠标,键盘等与页面交互**
**宽带网速**
**DNS服务器的响应速度**
**服务器的处理能力**
**
**数据库性能****
**路由转发**
**浏览器处理能力**
早在**2006年,雅虎就发布了提升站点性能的指南,Google也发布了类似的指南。而且有很多工具可以和浏览器一起工作,对你的Web页面的加载速度进行评估:分析页面中资源的数量,传输是否采用了压缩,JS、CSS是否进行了精简,有没有合理的使用缓存等等**。
**4.什么时候做性能优化最合适?**
一般来说,遵循避免过早优化的原则,因为网站再发过程中的成本相对来说还是比较高的,web开发工程师、ui、产品、运维、后台服务等等,所以第一我们要保证基本功能完成,再考虑优化。第二在没有找到性能瓶颈之前,不要优化
**5.哪方面需要做性能优化?**
在这之前,我们先分析一个页面从发起请求到展示到用户大概流程
(1)、**DNS 查询**
(2)、**发送 HTTP 请求**
(3)、**等待服务器响应**
(4)、**下载服务器响应内容**
(5)、**解析 HTML、CSS、JS**
(6)、**渲染 HTML、CSS、JS 和图片**
(7)、**响应用户事件**
了解了这几个过程,大家应该知道如何优化了吧,对!就是对症下药。
***6.优化的35条军规*:**
**1.尽量减少HTTP请求数:**
性能黄金法则:只有10%-20%的最终用户相应时间花在接收请求的HTML文档上,剩下的80%-90%时间花在HTML文档所引用的所有组件(图片,script,css,flash等等)进行的http请求上,减少组件数必然能够减少页面提交的HTTP请求数。这是让页面更快的关键。
减少页面组件数的一种方式是简化页面设计。但有没有一种方法可以在构建复杂的页面同时加快响应时间呢?嗯,确实有鱼和熊掌兼得的办法。
**合并文件**是通过把所有脚本放在一个文件中的方式来减少请求数的,当然,也可以合并所有的CSS。如果各个页面的脚本和样式不一样的话,合并文件就是一项比较麻烦的工作了,但把这个作为站点发布过程的一部分确实可以提高响应时间。
**
**CSS Sprites****是减少图片请求数量的首选方式。把背景图片都整合到一张图片中,然后用CSS的background-image和background-position属性来定位要显示的部分。
**图像映射**可以把多张图片合并成单张图片,总大小是一样的,但减少了请求数并加速了页面加载。图片映射只有在图像在页面中连续的时候才有用,比如导航条。给image map设置坐标的过程既无聊又容易出错,用image map来做导航也不容易,所以不推荐用这种方式。
**行内图片**(Base64编码)用data: URL模式来把图片嵌入页面。这样会增加HTML文件的大小,把行内图片放在(缓存的)样式表中是个好办法,而且成功避免了页面变“重”。但目前主流浏览器并不能很好地支持行内图片。
**缓存的力量是强大的**,恰当的缓存设置可以大大的减少 HTTP请求。假设某网站首页,当浏览器没有缓存的时候访问一共会发出 78个请求,共 600多 K数据,而当第二次访问即浏览器已缓存之后访问则仅有 10个请求,共 20多 K数据。 (这里需要说明的是,如果直接 F5刷新页面的话效果是不一样的,这种情况下请求数还是一样,不过被缓存资源的请求服务器是 304响应,只有 Header没有Body ,可以节省带宽 )
怎样才算合理设置 ?原则很简单,能缓存越多越好,能缓存越久越好。例如,很少变化的图片资源可以直接通过 HTTP Header中的Expires设置一个很长的过期头 ;变化不频繁而又可能会变的资源可以使用 Last-Modifed来做请求验证。尽可能的让资源能够在缓存中待得更久。关于 HTTP缓存的具体设置和原理此处就不再详述了。
减少页面的HTTP请求数是个起点,这是提升站点首次访问速度的重要指导原则。
**2.减少DNS查找**
域名系统建立了主机名和IP地址间的映射,就像电话簿上人名和号码的映射一样。当你在浏览器输入www.yahoo.com的时候,浏览器就会联系DNS解析器返回服务器的IP地址。DNS是有成本的,它需要20到120毫秒去查找给定主机名的IP地址。在DNS查找完成之前,浏览器无法从主机名下载任何东西。
DNS查找被缓存起来更高效,由用户的ISP(网络服务提供商)或者本地网络存在一个特殊的缓存服务器上,但还可以缓存在个人用户的计算机上。DNS信息被保存在操作系统的DNS cache(微软Windows上的”DNS客户端服务”)里。大多数浏览器有独立于操作系统的自己的cache。只要浏览器在自己的cache里还保留着这条记录,它就不会向操作系统查询DNS。
IE默认缓存DNS查找30分钟,写在DnsCacheTimeout注册表设置中。Firefox缓存1分钟,可以用network.dnsCacheExpiration配置项设置。(Fasterfox把缓存时间改成了1小时 P.S. Fasterfox是FF的一个提速插件)
如果客户端的DNS cache是空的(包括浏览器的和操作系统的),DNS查找数等于页面上不同的主机名数,包括页面URL,图片,脚本文件,样式表,Flash对象等等组件中的主机名,减少不同的主机名就可以减少DNS查找。
减少不同主机名的数量同时也减少了页面能够并行下载的组件数量,避免DNS查找削减了响应时间,而减少并行下载数量却增加了响应时间。我的原则是把组件分散在2到4个主机名下,这是同时减少DNS查找和允许高并发下载的折中方案。
**技巧1 – 使用快速DNS提供程序--->DNS提供商的速度**
**技巧2 – 更改TTL值以利用DNS缓存**
由于DNS缓存,你不必担心在每一个页面加载发生查找。这实际上是第一次请求。DNS缓存的工作方式与缓存WordPress站点的方式类似。DNS从缓存中提供,直到它到期。DNS高速缓存的长度取决于他们所谓的生存时间(TTL)值。TTL越高,浏览器执行另一次DNS查找的可能性就越小。
**技巧3 – 减少域名(主机名)**
减少您网站上DNS查询的最简单方法是简单地摆脱查询不同主机名的请求。 请记住,使用DNS查找不是关于请求的数量,而是关于不同域的数量。通过像Pingdom这样的工具运行你的WordPress站点,并确定每个请求是否真的有必要。由于DNS是一个主机名到IP的映射,你可能想知道为什么人们不只是指向一个IP呢?这是因为IP地址可以频繁更改,而主机名不会.
**提示4 – 使用更快的DNS使用替代服务**
**技巧5 – 在CDN上移动和托管资源**
减少DNS查询的最简单方法之一是将尽可能多的资源移动到您的CDN提供商。如果您通过Pingdom运行您的网站,则可以按域查看请求的总数,93.8%的请求是到CDN URL的。向主机发送一个请求,向Google Analytics发送一个请求。通过将尽可能多的资源移动到CDN,这减少了涉及的DNS查找次数,因此减少了加载时间。
**3.避免重定向**
重定向用301和302状态码,下面是一个有301状态码的HTTP头:
![](https://i.imgur.com/wfe40Sh.jpg)
浏览器会自动跳转到Location域指明的URL。重定向需要的所有信息都在HTTP头部,而响应体一般是空的。其实额外的HTTP头,比如Expires和Cache-Control也表示重定向。除此之外还有别的跳转方式:refresh元标签和JavaScript,但如果你必须得做重定向,最好用标准的3xxHTTP状态码,主要是为了让返回按钮能正常使用。
牢记重定向会拖慢用户体验,在用户和HTML文档之间插入重定向会延迟页面上的所有东西,页面无法渲染,组件也无法开始下载,直到HTML文档被送达浏览器。
有一种常见的极其浪费资源的重定向,而且web开发人员一般都意识不到这一点,就是URL尾部缺少一个斜线的时候。例如,跳转到http://astrology.yahoo.com/astrology会返回一个重定向到http://astrology.yahoo.com/astrology/的301响应(注意添在尾部的斜线)。在Apache中可以用Alias,mod_rewrite或者DirectorySlash指令来取消不必要的重定向。
重定向最常见的用途是把旧站点连接到新的站点,还可以连接同一站点的不同部分,针对用户的不同情况(浏览器类型,用户帐号类型等等)做一些处理。用重定向来连接两个网站是最简单的,只需要少量的额外代码。虽然在这些时候使用重定向减少了开发人员的开发复杂度,但降低了用户体验。一种替代方案是用Alias和mod_rewrite,前提是两个代码路径都在相同的服务器上。如果是因为域名变化而使用了重定向,就可以创建一条CNAME(创建一个指向另一个域名的DNS记录作为别名)结合Alias或者mod_rewrite指令。
**4.让Ajax可缓存**
Ajax的一个好处是可以给用户提供即时反馈,因为它能够从后台服务器异步请求信息。然而,用了Ajax就无法保证用户在等待异步JavaScript和XML响应返回期间不会非常无聊。在很多应用程序中,用户能够一直等待取决于如何使用Ajax。例如,在基于web的电子邮件客户端中,用户为了寻找符合他们搜索标准的邮件消息,将会保持对Ajax请求返回结果的关注。重要的是,要记得“异步”并不意味着“即时”。
要提高性能,优化这些Ajax响应至关重要。最重要的提高Ajax性能的方法就是让响应变得可缓存,就像在添上Expires或者Cache-Control HTTP头中讨论的一样。下面适用于Ajax的其它规则:
**Gzip组件:**
Gzip是目前最流行和最有效的压缩方法,由GNU开发然后标准化为RFC 1952。其他压缩方式有deflate等,但主流浏览器大部分都支持gzip,但有的不支持deflate,所以gzip是压缩方法的首选。
服务器会基于文件类型来选择gzip的压缩对象,大部分的网站压缩html文档,css,js文件,或者xml、json格式的返回结果。图片和pdf格式的文件一般不会压缩,因为它们已经被压缩了。尝试压缩这些文件不仅浪费cpu资源,反而有可能会增加压缩文件的大小。
gzip是有代价的,在服务器端进行压缩要付出额外的cpu资源,同样的在客户端解压也需要消耗cpu资源。权衡利弊要综合考虑响应的大小,带宽以及客户端和服务器之间的距离等因素。一般来说gzip可以降低响应大小的约70%左右,还是挺可观的
**减少DNS查找**:(参见上面2)
**压缩JavaScript**:
avaScript的压缩不是为了保护代码而压缩,而是压缩后的js代码文件可以小一倍甚至多倍,从而使这个js代码快速的下载到客户端,特别js文件较大时速度效果非常明显
**避免重定向**:(参见上面3)
**配置ETags**:
以前浏览器缓存的就会失效。
**什么是ETag**?
实体标签(EntityTag)是唯一标识了一个组件的一个特定版本的字符串,是web服务器用于确认缓存组件的有效性的一种机制,通常可以使用组件的某些属性来构造它。
条件GET请求
如果组件过期了,浏览器在重用它之前必须首先检查它是否有效。浏览器将发送一个条件GET请求到服务器,服务器判断缓存还有效,则发送一个304响应,告诉浏览器可以重用缓存组件。
那么服务器是根据什么判断缓存是否还有效呢?有两种方式:
ETag(实体标签);
最新修改日期;
最新修改日期
原始服务器通过Last-Modified响应头来返回组件的最新修改日期。
我们一起看看例子,一个Web 2.0的电子邮件客户端用了Ajax来下载用户的通讯录,以便实现自动完成功能。如果用户从上一次使用之后再没有修改过她的通讯录,而且Ajax响应是可缓存的,有尚未过期的Expires或者Cache-Control HTTP头,那么之前的通讯录就可以从缓存中读出。必须通知浏览器,应该继续使用之前缓存的通讯录响应,还是去请求一个新的。可以通过给通讯录的Ajax URL里添加一个表明用户通讯录最后修改时间的时间戳来实现,例如&t=1190241612。如果通讯录从上一次下载之后再没有被修改过,时间戳不变,通讯录就将从浏览器缓存中直接读出,从而避免一次额外的HTTP往返消耗。如果用户已经修改了通讯录,时间戳也可以确保新的URL不会匹配缓存的响应,浏览器将请求新的通讯录条目。
即使Ajax响应是动态创建的,而且可能只适用于单用户,它们也可以被缓存,而这样会让你的Web 2.0应用更快。
***5.延迟加载组件***
可以凑近看看页面并问自己:什么才是一开始渲染页面所必须的?其余内容都可以等会儿。
JavaScript是分隔onload事件之前和之后的一个理想选择。例如,如果有JavaScript代码和支持拖放以及动画的库,这些都可以先等会儿,因为拖放元素是在页面最初渲染之后的。其它可以延迟加载的部分包括隐藏内容(在某个交互动作之后才出现的内容)和折叠的图片。
工具可帮你减轻工作量:YUI Image Loader可以延迟加载折叠的图片,还有YUI Get utility是一种引入JS和CSS的简单方法。Yahoo!主页就是一个例子,可以打开Firebug的网络面板仔细看看。
最好让性能目标符合其它web开发最佳实践,比如“渐进增强”。如果客户端支持JavaScript,可以提高用户体验,但必须确保页面在不支持JavaScript时也能正常工作。所以,在确定页面运行正常之后,可以用一些延迟加载脚本增强它,以支持一些拖放和动画之类的华丽效果。
**6.预加载组件**
预加载可能看起来和延迟加载是相反的,但它其实有不同的目标。通过预加载组件可以充分利用浏览器空闲的时间来请求将来会用到的组件(图片,样式和脚本)。用户访问下一页的时候,大部分组件都已经在缓存里了,所以在用户看来页面会加载得更快。
实际应用中有以下几种预加载的类型:
无条件预加载——尽快开始加载,获取一些额外的组件。google.com就是一个sprite图片预加载的好例子,这个sprite图片并不是google.com主页需要的,而是搜索结果页面上的内容。
条件性预加载——根据用户操作猜测用户将要跳转到哪里并据此预加载。在search.yahoo.com的输入框里键入内容后,可以看到那些额外组件是怎样请求加载的。
提前预加载——在推出新设计之前预加载。经常在重新设计之后会听到:“这个新网站不错,但比以前更慢了”,一部分原因是用户访问先前的页面都是有旧缓存的,但新的却是一种空缓存状态下的体验。可以通过在将要推出新设计之前预加载一些组件来减轻这种负面影响,老站可以利用浏览器空闲的时间来请求那些新站需要的图片和脚本。
***7.减少DOM元素的数量***
一个复杂的页面意味着要下载更多的字节,而且用JavaScript访问DOM也会更慢。举个例子,想要添加一个事件处理器的时候,循环遍历页面上的500个DOM元素和5000个DOM元素是有区别的。
大量的DOM元素是一种征兆——页面上有些内容无关的标记需要清理。正在用嵌套表格来布局吗?还是为了修复布局问题而添了一堆的<div>s?或许应该用更好的语义化标记。
YUI CSS utilities对布局有很大帮助:grids.css针对整体布局,fonts.css和reset.css可以用来去除浏览器的默认格式。这是个开始清理和思考标记的好机会,例如只在语义上有意义的时候使用<div>,而不是因为它能够渲染一个新行。
**8.跨域分离组件**
分离组件可以最大化并行下载,但要确保只用不超过2-4个域,因为存在DNS查找的代价。例如,可以把HTML和动态内容部署在www.example.org,而把静态组件分离到static1.example.org和static2.example.org
**9.尽量少用iframe**
用iframe可以把一个HTML文档插入到父文档里,重要的是明白iframe是如何工作的并高效地使用它。
iframe的优点:
引入缓慢的第三方内容,比如标志和广告
安全沙箱
并行下载脚本
iframe的缺点:
代价高昂,即使是空白的iframe
阻塞页面加载
非语义
**10.杜绝404**
HTTP请求代价高昂,完全没有必要用一个HTTP请求去获取一个无用的响应(比如404 Not Found),只会拖慢用户体验而没有任何好处。
有些站点用的是有帮助的404——“你的意思是xxx?”,这样做有利于用户体验,,但也浪费了服务器资源(比如数据库等等)。最糟糕的是链接到的外部JavaScript有错误而且结果是404。首先,这种下载将阻塞并行下载。其次,浏览器会试图解析404响应体,因为它是JavaScript代码,需要找出其中可用的部分。
**CSS部分**
**11.避免使用CSS表达式**
用CSS表达式动态设置CSS属性,是一种强大又危险的方式。从IE5开始支持,但从IE8起就不推荐使用了。
**12.选择<link>舍弃@import**
前面提到了一个最佳实践:为了实现逐步渲染,CSS应该放在顶部。
在IE中用@import与在底部用<link>效果一样,所以最好不要用它。
**13.避免使用滤镜**
IE专有的AlphaImageLoader滤镜可以用来修复IE7之前的版本中半透明PNG图片的问题。在图片加载过程中,这个滤镜会阻塞渲染,卡住浏览器,还会增加内存消耗而且是被应用到每个元素的,而不是每个图片,所以会存在一大堆问题。
最好的方法是干脆不要用AlphaImageLoader,而优雅地降级到用在IE中支持性很好的PNG8图片来代替。如果非要用AlphaImageLoader,应该用下划线hack:_filter来避免影响IE7及更高版本的用户。
**14.把样式表放在顶部**
在Yahoo!研究性能的时候,我们发现把样式表放到文档的HEAD部分能让页面看起来加载地更快。这是因为把样式表放在head里能让页面逐步渲染。
关注性能的前端工程师想让页面逐步渲染。也就是说,我们想让浏览器尽快显示已有内容,这在页面上有一大堆内容或者用户网速很慢时显得尤为重要。给用户显示反馈(比如进度指标)的重要性已经被广泛研究过,并且被记录下来了。在我们的例子中,HTML页面就是进度指标!当浏览器逐渐加载页面头部,导航条,顶部logo等等内容的时候,这些都被正在等待页面加载的用户当作反馈,能够提高整体用户体验。
**js部分:**
**15.去除重复脚本**
页面含有重复的脚本文件会影响性能,这可能和你想象的不一样。在对美国前10大web站点的评审中,发现只有2个站点含有重复脚本。两个主要原因增加了在单一页面中出现重复脚本的几率:团队大小和脚本数量。在这种情况下,重复脚本会创建不必要的HTTP请求,执行无用的JavaScript代码,而影响页面性能。
IE会产生不必要的HTTP请求,而Firefox不会。在IE中,如果一个不可缓存的外部脚本被页面引入了两次,它会在页面加载时产生两个HTTP请求。即使脚本是可缓存的,在用户重新加载页面时也会产生额外的HTTP请求。
除了产生没有意义的HTTP请求之外,多次对脚本求值也会浪费时间。因为无论脚本是否可缓存,在Firefox和IE中都会执行冗余的JavaScript代码。
避免不小心把相同脚本引入两次的一种方法就是在模版系统中实现脚本管理模块。典型的脚本引入方法就是在HTML页面中用SCRIPT标签:
1
<script type="text/javascript" src="menu_1.0.17.js"></script>
**16.尽量减少DOM访问**
用JavaScript访问DOM元素是很慢的,所以,为了让页面反应更迅速,应该:
缓存已访问过的元素的索引
先“离线”更新节点,再把它们添到DOM树上
避免用JavaScript修复布局问题
**17.用智能的事件处理器**
有时候感觉页面反映不够灵敏,是因为有太多频繁执行的事件处理器被添加到了DOM树的不同元素上,这就是推荐使用事件委托的原因。如果一个div里面有10个按钮,应该只给div容器添加一个事件处理器,而不是给每个按钮都添加一个。事件能够冒泡,所以可以捕获事件并得知哪个按钮是事件源。
**18.把脚本放在底部**
脚本会阻塞并行下载,HTTP/1.1官方文档建议浏览器每个主机名下并行下载的组件数不要超过两个,如果图片来自多个主机名,并行下载的数量就可以超过两个。如果脚本正在下载,浏览器就不开始任何其它下载任务,即使是在不同主机名下的。
有时候,并不容易把脚本移动到底部。举个例子,如果脚本是用document.write插入到页面内容中的,就没办法再往下移了。还可能存在作用域问题,在多数情况下,这些问题都是可以解决的。
一个常见的建议是用推迟(deferred)脚本,有DEFER属性的脚本意味着不能含有document.write,并且提示浏览器告诉他们可以继续渲染。不幸的是,Firefox不支持DEFER属性。在IE中,脚本可能被推迟,但不尽如人意。如果脚本可以推迟,我们就可以把它放到页面底部,页面就可以更快地载入。
**javascript css 部分**
**19.把JavaScript和CSS放到外面**
很多性能原则都是关于如何管理外部组件的,然而,在这些顾虑出现之前你应该问一个更基础的问题:应该把JavaScript和CSS放到外部文件中还是直接写在页面里?
实际上,用外部文件可以让页面更快,因为JavaScript和CSS文件会被缓存在浏览器。HTML文档中的行内JavaScript和CSS在每次请求该HTML文档的时候都会重新下载。这样做减少了所需的HTTP请求数,但增加了HTML文档的大小。另一方面,如果JavaScript和CSS在外部文件中,并且已经被浏览器缓存起来了,那么我们就成功地把HTML文档变小了,而且还没有增加HTTP请求数。
**20.压缩JavaScript和CSS**
压缩具体来说就是从代码中去除不必要的字符以减少大小,从而提升加载速度。代码最小化就是去掉所有注释和不必要的空白字符(空格,换行和tab)。在JavaScript中这样做能够提高响应性能,因为要下载的文件变小了。两个最常用的JavaScript代码压缩工具是JSMin和YUI Compressor,YUI compressor还可以压缩CSS。
混淆是一种可选的源码优化措施,要比压缩更复杂,所以混淆过程也更容易产生bug。在对美国前十的网站调查中,压缩可以缩小21%,而混淆能缩小25%。虽然混淆的缩小程度更高,但比压缩风险更大。
除了压缩外部脚本和样式,行内的<script>和<style>块也可以压缩。即使启用了gzip模块,先进行压缩也能够缩小5%或者更多的大小。JavaScript和CSS的用处越来越多,所以压缩代码会有不错的效果。
**
**图片****
**21.优化图片**
尝试把GIF格式转换成PNG格式,看看是否节省空间。在所有的PNG图片上运行pngcrush(或者其它PNG优化工具)
**22.优化CSS Sprite**
在Sprite图片中横向排列一般都比纵向排列的最终文件小
组合Sprite图片中的相似颜色可以保持低色数,最理想的是256色以下PNG8格式
“对移动端友好”,不要在Sprite图片中留下太大的空隙。虽然不会在很大程度上影响图片文件的大小,但这样做可以节省用户代理把图片解压成像素映射时消耗的内存。100×100的图片是1万个像素,而1000×1000的图片就是100万个像素了。
2**3.不要用HTML缩放图片**
不要因为在HTML中可以设置宽高而使用本不需要的大图。如果需要
(https://img-blog.csdnimg.cn/20190308212131620.png)
那么图片本身(mycat.jpg)应该是100x100px的,而不是去缩小500x500px的图片。
**24.用小的可缓存的favicon.ico(P.S. 收藏夹图标)**
favicon.ico是放在服务器根目录的图片,它会带来一堆麻烦,因为即便你不管它,浏览器也会自动请求它,所以最好不要给一个404 Not Found响应。而且只要在同一个服务器上,每次请求它时都会发送cookie,此外这个图片还会干扰下载顺序,例如在IE中,当你在onload中请求额外组件时,将会先下载favicon。
所以为了缓解favicon.ico的缺点,应该确保:
足够小,最好在1K以下
设置合适的有效期HTTP头(以后如果想换的话就不能重命名了),把有效期设置为几个月后一般比较安全,可以通过检查当前favicon.ico的最后修改日期来确保变更能让浏览器知道。
**cookie**
**25.给Cookie减肥**
使用cookie的原因有很多,比如授权和个性化。HTTP头中cookie信息在web服务器和浏览器之间交换。重要的是保证cookie尽可能的小,以最小化对用户响应时间的影响。
清除不必要的cookie
保证cookie尽可能小,以最小化对用户响应时间的影响
注意给cookie设置合适的域级别,以免影响其它子域
设置合适的有效期,更早的有效期或者none可以更快的删除cookie,提高用户响应时间
**26.把组件放在不含cookie的域下**
当浏览器发送对静态图像的请求时,cookie也会一起发送,而服务器根本不需要这些cookie。所以它们只会造成没有意义的网络通信量,应该确保对静态组件的请求不含cookie。可以创建一个子域,把所有的静态组件都部署在那儿。
如果域名是www.example.org,可以把静态组件部署到static.example.org。然而,如果已经在顶级域example.org或者www.example.org设置了cookie,那么所有对static.example.org的请求都会含有这些cookie。这时候可以再买一个新域名,把所有的静态组件部署上去,并保持这个新域名不含cookie。Yahoo!用的是yimg.com,YouTube是ytimg.com,Amazon是images-amazon.com等等。
把静态组件部署在不含cookie的域下还有一个好处是有些代理可能会拒绝缓存带cookie的组件。有一点需要注意:如果不知道应该用example.org还是www.example.org作为主页,可以考虑一下cookie的影响。省略www的话,就只能把cookie写到*.example.org,所以因为性能原因最好用www子域,并且把cookie写到这个子域下。
**移动端 **
**27.保证所有组件都小于25K**
这个限制是因为iPhone不能缓存大于25K的组件,注意这里指的是未压缩的大小。这就是为什么缩减内容本身也很重要,因为单纯的gzip可能不够。
**28.把组件打包到一个复合文档里**
把各个组件打包成一个像有附件的电子邮件一样的复合文档里,可以用一个HTTP请求获取多个组件(记住一点:HTTP请求是代价高昂的)。用这种方式的时候,要先检查用户代理是否支持(iPhone就不支持)。
**服务器**
**29.Gzip组件**
前端工程师可以想办法明显地缩短通过网络传输HTTP请求和响应的时间。毫无疑问,终端用户的带宽速度,网络服务商,对等交换点的距离等等,都是开发团队所无法控制的。但还有别的能够影响响应时间的因素,压缩可以通过减少HTTP响应的大小来缩短响应时间。
从HTTP/1.1开始,web客户端就有了支持压缩的Accept-Encoding HTTP请求头。
Accept-Encoding: gzip, deflate
如果web服务器看到这个请求头,它就会用客户端列出的一种方式来压缩响应。web服务器通过Content-Encoding相应头来通知客户端。
Content-Encoding: gzip
尽可能多地用gzip压缩能够给页面减肥,这也是提升用户体验最简单的方法。
**30.避免图片src属性为空**
Image with empty string src属性是空字符串的图片很常见,主要以两种形式出现:
(https://img-blog.csdnimg.cn/20190308211950109.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDQ2NTU4NA==,size_16,color_FFFFFF,t_70)
这两种形式都会引起相同的问题:浏览器会向服务器发送另一个请求。
**31.配置ETags**
实体标签(ETags),是服务器和浏览器用来决定浏览器缓存中组件与源服务器中的组件是否匹配的一种机制(“实体”也就是组件:图片,脚本,样式表等等)。添加ETags可以提供一种实体验证机制,比最后修改日期更加灵活。一个ETag是一个字符串,作为一个组件某一具体版本的唯一标识符。唯一的格式约束是字符串必须用引号括起来,源服务器用相应头中的ETag来指定组件的ETag:
HTTP/1.1 200 OK
Last-Modified: Tue, 12 Dec 2006 03:03:59 GMT
ETag: "10c24bc-4ab-457e1c1f"
Content-Length: 12195
然后,如果浏览器必须验证一个组件,它用If-None-Match请求头来把ETag传回源服务器。如果ETags匹配成功,会返回一个304状态码,这样就减少了12195个字节的响应体。
GET /i/yahoo.gif HTTP/1.1
Host: us.yimg.com
If-Modified-Since: Tue, 12 Dec 2006 03:03:59 GMT
If-None-Match: "10c24bc-4ab-457e1c1f"
HTTP/1.1 304 Not Modified
**32.对Ajax用GET请求**
Yahoo!邮箱团队发现使用XMLHttpRequest时,浏览器的POST请求是通过一个两步的过程来实现的:先发送HTTP头,在发送数据。所以最好用GET请求,它只需要发送一个TCP报文(除非cookie特别多)。IE的URL长度最大值是2K,所以如果要发送的数据超过2K就无法使用GET了。
POST请求的一个有趣的副作用是实际上没有发送任何数据,就像GET请求一样。正如HTTP说明文档中描述的,GET请求是用来检索信息的。所以它的语义只是用GET请求来请求数据,而不是用来发送需要存储到服务器的数据。
**33.尽早清空缓冲区**
当用户请求一个页面时,服务器需要用大约200到500毫秒来组装HTML页面,在这期间,浏览器闲等着数据到达。PHP中有一个flush()函数,允许给浏览器发送一部分已经准备完毕的HTML响应,以便浏览器可以在后台准备剩余部分的同时开始获取组件,好处主要体现在很忙的后台或者很“轻”的前端页面上(P.S. 也就是说,响应时耗主要在后台方面时最能体现优势)。
较理想的清空缓冲区的位置是HEAD后面,因为HTML的HEAD部分通常更容易生成,并且允许引入任何CSS和JavaScript文件,这样就可以让浏览器在后台还在处理的时候就开始并行获取组件。
例如:
... <!-- css, js -->
</head>
<?php flush(); ?>
<body>
... <!-- content -->
**34.使用CDN(内容分发网络)**
用户与服务器的物理距离对响应时间也有影响。把内容部署在多个地理位置分散的服务器上能让用户更快地载入页面。但具体要怎么做呢?
实现内容在地理位置上分散的第一步是:不要尝试去重新设计你的web应用程序来适应分布式结构。这取决于应用程序,改变结构可能包括一些让人望而生畏的任务,比如同步会话状态和跨服务器复制数据库事务(翻译可能不准确)。缩短用户和内容之间距离的提议可能被推迟,或者根本不可能通过,就是因为这个难题。
记住终端用户80%到90%的响应时间都花在下载页面组件上了:图片,样式,脚本,Flash等等,这是业绩黄金法则。最好先分散静态内容,而不是一开始就重新设计应用程序结构。这不仅能够大大减少响应时间,还更容易表现出CDN的功劳。
内容分发网络(CDN)是一组分散在不同地理位置的web服务器,用来给用户更高效地发送内容。典型地,选择用来发送内容的服务器是基于网络距离的衡量标准的。例如:选跳数(hop)最少的或者响应时间最快的服务器。
**35.添上Expires或者Cache-Control HTTP头**
这条规则有两个方面:
对于静态组件:通过设置一个遥远的将来时间作为Expires来实现永不失效
多余动态组件:用合适的Cache-ControlHTTP头来让浏览器进行条件性的请求
网页设计越来越丰富,这意味着页面里有更多的脚本,图片和Flash。站点的新访客可能还是不得不提交几个HTTP请求,但通过使用有效期能让组件变得可缓存,这避免了在接下来的浏览过程中不必要的HTTP请求。有效期HTTP头通常被用在图片上,但它们应该用在所有组件上,包括脚本、样式和Flash组件。
浏览器(和代理)用缓存来减少HTTP请求的数目和大小,让页面能够更快加载。web服务器通过有效期HTTP响应头来告诉客户端,页面的各个组件应该被缓存多久。用一个遥远的将来时间做有效期,告诉浏览器这个响应在2010年4月15日前不会改变。
Expires: Thu, 15 Apr 2010 20:00:00 GMT
如果你用的是Apache服务器,用ExpiresDefault指令来设置相对于当前日期的有效期。下面的例子设置了从请求时间起10年的有效期:
ExpiresDefault "access plus 10 years"