注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Follow your heart

 
 
 

日志

 
 

再谈yahoo网站性能优化的建议  

2011-12-08 16:08:54|  分类: SEO之路 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

本来这是个老生常谈的问题,上周自成又分享了一些性能优化的建议,我这里再做一个全面的Tips整理,谨作为查阅型的文档,不妥之处,还请指正;

一、 Yahoo的军规条例:

谨记:80%-90%的终端响应时间是花费在下载页面中的图片,样式表,脚本,flash等;
详细的解释来这里查:http://developer.yahoo.com/performance/rules.html
也可以直接firebug上一项项比对,如下图:

再谈yahoo网站性能优化的建议 - 若水三千 - Follow your heart

简单翻译解释下:

1、尽量减少HTTP请求个数——须权衡

合并图片(如css sprites,内置图片使用数据)、合并CSS、JS,这一点很重要,但是要考虑合并后的文件体积。

2、使用CDN(内容分发网络)

这里可以关注CDN的三类实现:镜像、高速缓存、专线,以及智能路由器和负载均衡;

3、为文件头指定Expires或Cache-Control,使内容具有缓存性。

区分静态内容和动态内容,避免以后页面访问中不必要的HTTP请求。

4、避免空的src和href

留意具有这两个属性的标签如link,script,img,iframe等;

5、使用gzip压缩内容

Gzip压缩所有可能的文件类型以来减少文件体积

6、把CSS放到顶部

实现页面有秩序地加载,这对于拥有较多内容的页面和网速较慢的用户来说更为重要,同时,HTML规范清楚指出样式表要放包含在页面的<head />区域内;

7、把JS放到底部

HTTP/1.1 规范建议,浏览器每个主机名的并行下载内容不超过两个,而问题在于脚本阻止了页面的平行下载,即便是主机名不相同

8、避免使用CSS表达式

页面显示和缩放,滚动、乃至移动鼠标时,CSS表达式的计算频率是我们要关注的。可以考虑一次性的表达式或者使用事件句柄来代替CSS表达式。

9、将CSS和JS放到外部文件中

我们需要权衡内置代码带来的HTTP请求减少与通过使用外部文件进行缓存带来的好处的折中点。

10、减少DNS查找次数

我们需要权衡减少 DNS查找次数和保持较高程度并行下载两者之间的关系。

11、精简CSS和JS

目的就是减少下载的文件体积,可考虑压缩工具JSMin和YUI Compressor。

12、避免跳转

为了确保“后退”按钮可以正确地使用,使用标准的 3XXHTTP状态代码;同域中注意避免反斜杠 “/” 的跳转;
跨域使用 Alias或者 mod_rewirte建立 CNAME(保存一个域名和另外一个域名之间关系的DNS记录)

13、剔除重复的JS和CSS

重复调用脚本,除了增加额外的HTTP请求外,多次运算也会浪费时间。在IE和Firefox中不管脚本是否可缓存,它们都存在重复运算JavaScript的问题。

14、配置ETags

Entity tags(ETags)(实体标签)是web服务器和浏览器用于判断浏览器缓存中的内容和服务器中的原始内容是否匹配的一种机制(“实体”就是所说的“内 容”,包括图片、脚本、样式表等),是比last-modified date更更加灵活的机制,单位时间内文件被修过多次,Etag可以综合Inode(文件的索引节点(inode)数),MTime(修改时间)和Size来精准的进行判断,避开UNIX记录MTime只能精确到秒的问题。 服务器集群使用,可取后两个参数。使用ETags减少Web应用带宽和负载。

15、使AJAX可缓存

利用时间戳,更精巧的实现响应可缓存与服务器数据同步更新。

16、尽早刷新输出缓冲

尤其对于css,js文件的并行下载更有意义

17、使用GET来完成AJAX请求

当使用XMLHttpRequest时,浏览器中的POST方法是一个“两步走”的过程:首先发送文件头,然后才发送数据。在url小于2K时使用GET获取数据时更加有意义。

18、延迟加载

确定页面运行正常后,再加载脚本来实现如拖放和动画,或者是隐藏部分的内容以及折叠内容等。

19、预加载

关注下无条件加载,有条件加载和有预期的加载。

20、减少DOM元素个数

使用更适合或者在语意是更贴切的标签,要考虑大量DOM元素中循环的性能开销。

21、根据域名划分页面内容

很显然, 是最大限度地实现平行下载

22、尽量减少iframe的个数

考虑即使内容为空,加载也需要时间,会阻止页面加载,没有语意,注意iframe相对于其他DOM元素高出1-2个数量级的开销,它会在典型方式下阻塞onload事件,IE和Firefox中主页面样式表会阻塞它的下载。

23、避免404

HTTP请求时间消耗是很大的,有些站点把404错误响应页面改为“你是不是要找***”,这虽然改进了用户体验但是同样也会浪费服务器资源(如数据库等)。最糟糕的情况是指向外部 JavaScript的链接出现问题并返回404代码。首先,这种加载会破坏并行加载;其次浏览器会把试图在返回的404响应内容中找到可能有用的部分当作JavaScript代码来执行。

24、减少Cookie的大小

去除不必要的coockie
使coockie体积尽量小以减少对用户响应的影响
注意在适应级别的域名上设置coockie以便使子域名不受影响
设置合理的过期时间。较早地Expire时间和不要过早去清除coockie,都会改善用户的响应时间。

25、使用无cookie的域

确定对于静态内容的请求是无coockie的请求。创建一个子域名并用他来存放所有静态内容。

26、减少DOM访问

缓存已经访问过的有关元素
线下更新完节点之后再将它们添加到文档树中
避免使用JavaScript来修改页面布局

27、开发智能事件处理程序

有时候我们会感觉到页面反应迟钝,这是因为DOM树元素中附加了过多的事件句柄并且些事件句病被频繁地触发。这就是为什么说使用event delegation(事件代理)是一种好方法了。如果你在一个div中有10个按钮,你只需要在div上附加一次事件句柄就可以了,而不用去为每一个按 钮增加一个句柄。事件冒泡时你可以捕捉到事件并判断出是哪个事件发出的。
你同样也不用为了操作DOM树而等待onload事件的发生。你需要做的就是等待树结构中你要访问的元素出现。你也不用等待所有图像都加载完毕。
你可能会希望用DOMContentLoaded事件来代替 事件应用程序中的onAvailable方法。

28、用<link>代替@import

在IE中,页面底部@import和使用<link>作用是一样的,因此最好不要使用它。

29、避免使用滤镜

完全避免使用AlphaImageLoader的最好方法就是使用PNG8格式来代替,这种格式能在IE中很好地工作。如果你确实需要使用 AlphaImageLoader,请使用下划线_filter又使之对IE7以上版本的用户无效。

30、优化图像

尝试把GIF格式转换成PNG格式,看看是否节省空间。在所有的PNG图片上运行pngcrush(或者其它PNG优化工具)

31、优化CSS Spirite

在Spirite中水平排列你的图片,垂直排列会稍稍增加文件大小;
Spirite中把颜色较近的组合在一起可以降低颜色数,理想状况是低于256色以便适用PNG8格式;
便于移动,不要在Spirite的图像中间留有较大空隙。这虽然不大会增加文件大小但对于用户代理来说它需要更少的内存来把图片解压为像素地图。 100×100的图片为1万像素,而1000×1000就是100万像素。

32、不要在HTML中缩放图像——须权衡

不要为了在HTML中设置长宽而使用比实际需要大的图片。如果你需要:

<img width=”100″ height=”100″ src=”mycat.jpg” alt=”My Cat” />

那么你的图片(mycat.jpg)就应该是100×100像素而不是把一个500×500像素的图片缩小使用。这里在下文有更有趣的分析。

33、favicon.ico要小而且可缓存

favicon.ico是位于服务器根目录下的一个图片文件。它是必定存在的,因为即使你不关心它是否有用,浏览器也会对它发出请求,因此最好不要返回一 个404 Not Found的响应。由于是在同一台服务器上,它每被请求一次coockie就会被发送一次。这个图片文件还会影响下载顺序,例如在IE中当你在 onload中请求额外的文件时,favicon会在这些额外内容被加载前下载。

因此,为了减少favicon.ico带来的弊端,要做到:
文件尽量地小,最好小于1K
在适当的时候(也就是你不要打算再换favicon.ico的时候,因为更换新文件时不能对它进行重命名)为它设置Expires文件头。你可以很安全地 把Expires文件头设置为未来的几个月。你可以通过核对当前favicon.ico的上次编辑时间来作出判断。
Imagemagick可以帮你创建小巧的favicon。

34、保持单个内容小于25K

因为iPhone不能缓存大于25K的文件。注意这里指的是解压缩后的大小。由于单纯gizp压缩可能达不要求,因此精简文件就显得十分重 要。

35、打包组件成复合文本

页面内容打包成复合文本就如同带有多附件的Email,它能够使你在一个HTTP请求中取得多个组件(切记:HTTP请求是很奢侈的)。当你使用这条规 则时,首先要确定用户代理是否支持(iPhone就不支持)。

二、Yahoo军规之外的场景?

1、 使用json作为数据的交换格式
Json在浏览器解析的效率至少高于XML一个数量级,高级浏览器中内置的有生成和解析json的方法,IE6中要用额外的方法(http://json.org),不要用eval,容易引发性能和安全问题。
2、 尽可能对images和table设定宽高值

针对Yslow的不要在HTML中缩放图像——第33条,有人会误解为不要对图片加宽高值,其实这条建议本身的意思是不要为了获取一个特定大小的图片,而去强行通过设置宽高值拉伸或者压缩一个既有的图片。建议是另存一张符合尺寸的图片替代。
对图片和table是设定宽高,是考虑到如果浏览器能立刻知道图片或者tables的宽高,它就能够直接呈现页面而不需要通过计算元素大小后重绘,而且即便是图片损毁而没有展现,也不会进而破坏了页面本来的布局。
有一些应用场景需要注意:

  • a、批量图片,图片源可控同时页面图片宽高值不可变,比如数据库有100张100*100的图片要在页面中全部展示,那么建议是都写上

    <img width=”100″ height=”120″ src=”" alt=”" />

  • b、批量图片,图片源不可控同时页面图片宽高值不可变,比如数据库有100张图片,而已知图片有的尺寸是97*100,有的100*105,而又不可能去一张张修改另存。这里视情况而定,根据图片尺寸与要求尺寸的偏离度,在保证图片不拉伸变形同时不影响页面布局的情况下,可以对图片单独设定宽度100,同时对其包裹的容器设定100*100的宽高来隐藏多出来的部分,注意不能同时设置宽高以防止变形。
  • c、批量图片,图片源不可控,页面图片宽高值不定,比如数据库有100张各种尺寸偏差较大的,此时可不对图片设置宽高;
    其他情况不一一罗列,原则是在最大程度保证图片不变形与图片最大面积展现的前提下,尽可能为图片设置宽高值,总之就是权衡。
    Tables的宽高值同图片,尽可能设置。
  • 3、 拆离内容块

    尽量用div取代tables,或者将tables打破成嵌套层次深的结构;

    避免用这样的嵌套

    <table>  <table>   <table>    ...   </table>  </table> </table> 

    采用下面的或者div重构:

    <table></table> <table></table> <table></table> 

    4、 高效的CSS书写规则

    众所周知,CSS选择符是从右向左进行匹配的。
    通常一个图片列表的的小模块

    <div id="box">  <div class="hd">   <h3>我的旅途</h3>  </div>  <div class="bd">   <h4>旅途1</h4>   <ul id="pics">    <li>     <a href="#pic" title=""><img src="" alt="" /> </a>     <p>这是在<strong>图片1</strong></p>    </li>   </ul>  </div> </div> 

    为了代码上缩进后内层的整洁性,我们html有可能这样写之外,更喜欢看这样的css写法:

    .box{border:1px solid #ccc } .box .hd{border-bottom:1px solid #ccc } .box .hd h3{color:#515151} .box .bd{color:#404040 } .box .bd ul{margin-left:10px} .box .bd ul li{border-bottom:1px dashed #f1f1f1} .box .bd ul li a{text-decoration:none} .box .bd ul li a:hover{text-decoration:underline} .box .bd ul li a img{border:1px solid #ccc} .box .bd ul li p{text-align:left;} .box .bd ul li p strong{color:#ff6600} 

    其实写到这里,问题已经显而易见了。深达五层抑或六层的嵌套,同时右边的选择符都是采用标签,在满足我们视觉平整与代码结构系统化的时候,付出的是性能的代价。

    不做进一步的代码书写方式的探讨,受个人习惯与应用场景影响。这里对css选择符按照开销从小到大的顺序梳理一下:

  • ID选择符 #box
  • 类选择符 .box
  • 类型选择符 div
  • 相邻兄弟选择符 h4 + #pics
  • 子选择符 #pics li
  • 后代选择符 .box a{}
  • 通配选择符 *
  • 属性选择符 [href=”#pic”]
  • 伪类和伪元素 a:hover

参考《高性能网站建设-进阶指南》,有如下建议:

  • 避免使用统配规则;
  • 不要限定ID选择符;
  • 不要限定类选择符;
  • 让规则越具体越好;
  • 避免使用后代选择符;
  • 避免使用标签-子选择符;
  • 质疑子选择符的所有用途;
  • 依靠继承;

还要注意到,即便是页面加载后,当页面被触发引起回流(reflow)的时候,低效的选择符依然会引发更高的开销,显然这对于用户是不佳的体验。

4、Javascript 的性能优化点

  • a、慎用Eval

    谨记:有“eval”的代码比没有“eval”的代码要慢上 100 倍以上。主要原因是:JavaScript 代码在执行前会进行类似“预编译”的操作:首先会创建一个当前执行环境下的活动对象,并将那些用 var 申明的变量设置为活动对象的属性,但是此时这些变量的赋值都是 undefined,并将那些以 function 定义的函数也添加为活动对象的属性,而且它们的值正是函数的定义。但是,如果你使用了“eval”,则“eval”中的代码(实际上为字符串)无法预先识别其上下文,无法被提前解析和优化,即无法进行预编译的操作。所以,其性能也会大幅度降低。

  • b、推荐尽量使用局部变量

    JavaScript 代码解释执行,在进入函数内部时,它会预先分析当前的变量,并将这些变量归入不同的层级(level),一般情况下:
    局部变量放入层级 1(浅),全局变量放入层级 2(深)。如果进入“with”或“try – catch”代码块,则会增加新的层级,即将“with”或“catch”里的变量放入最浅层(层 1),并将之前的层级依次加深。变量所在的层越浅,访问(读取或修改)速度越快,尤其是对于大量使用全局变量的函数里面。

  • c、字符串数组方式拼接避免在IE6下的开销

    var tips = 'tip1'+'tip2'; 

    这是我们拼接字符串常用的方式,但是这种方式会有一些临时变量的创建和销毁,影响性能,尤其是在IE6下,所以推荐使用如下方式拼接:

    var tip_array = [],tips; tip_array.push('tip1'); tip_array.push('tip2'); tips = tip_array.join(''); 

    当然,最新的浏览器(如火狐 Firefox3+,IE8+ 等等)对字符串的拼接做了优化,性能略快于数组的“join”方法。

  • 以上仅列出三种常见的优化方法,仅抛砖以引玉石,更多的javascript优化点,比如避免隐式类型转换, 缩小对象访问层级,利用变量优化字符串匹配等大家可以继续深入挖掘;

5、DOM 操作优化

首先澄清两个概念——Repaint 和 Reflow:Repaint 也叫 Redraw,它指的是一种不会影响当前 DOM 的结构和布局的一种重绘动作。如下动作会产生 Repaint 动作:

  • 不可见到可见(visibility 样式属性);
  • 颜色或图片变化(background, border-color, color 样式属性);
  • 不改变页面元素大小,形状和位置,但改变其外观的变化

Reflow 比起 Repaint 来讲就是一种更加显著的变化了。它主要发生在 DOM 树被操作的时候,任何改变 DOM 的结构和布局都会产生 Reflow。但一个元素的 Reflow 操作发生时,它的所有父元素和子元素都会放生 Reflow,最后 Reflow 必然会导致 Repaint 的产生。举例说明,如下动作会产生 Reflow 动作:

  • 浏览器窗口的变化;
  • DOM 节点的添加删除操作
  • 一些改变页面元素大小,形状和位置的操作的触发
  • 通过 Reflow 和 Repaint 的介绍可知,每次 Reflow 比其 Repaint 会带来更多的资源消耗,因此,我们应该尽量减少 Reflow 的发生,或者将其转化为只会触发 Repaint 操作的代码。

    var tipBox = document.createElement('div'); document.body.appendChild('tipBox');//reflow var tip1 = document.createElement('div'); var tip2 = document.createElement('div'); tipBox.appendChild(tip1);//reflow tipBox.appendChild(tip2);//reflow 

    如上的代码,会产生三次reflow,优化后的代码如下:

    var tipBox = document.createElement('div');    tip1 = document.createElement('div');    tip2 = document.createElement('div'); tipBox.appendChild(tip1); tipBox.appendChild(tip2); document.body.appendChild('tipBox');//reflow 

    当然还可以利用 display 来减少reflow次数

    var tipBox = document.getElementById('tipBox'); tipBox.style.display = 'none';//reflow tipBox.appendChild(tip1); tipBox.appendChild(tip2); tipBox.appendChild(tip3); tipBox.appendChild(tip4); tipBox.appendChild(tip5); tipBox.style.width = 120; tipBox.style.height = 60; tipBox.style.display = 'block';//reflow 

    DOM元素测量属性和方法也会触发reflow,如下:

    var tipWidth = tipBox.offsetWidth;//reflow    tipScrollLeft = tipBox.scrollLeft;//reflow    display = window.getComputedStyle(div,'').getPropertyValue('display');//reflow 

    触发reflow的属性和方法大概有这些:

    • offsetLeft
    • offsetTop
    • offsetHeight
    • offsetWidth
    • scrollTop/Left/Width/Height
    • clientTop/Left/Width/Height
    • getComputedStyle()
    • currentStyle(in IE))

    我们可以用临时变量将“offsetWidth”的值缓存起来,这样就不用每次访问“offsetWidth”属性。这种方式在循环里面非常适用,可以极大地提高性能。

    如果有批量的样式属性需要修改,建议通过替换className的方式来降低reflow的次数,曾经有这样一个场景:有三个intput,分别对应下面三个图片和三个内容区域,第二input选中的时候,第二图片显示,其他图片隐藏,第二块内容显示,其他内容隐藏,直接操作DOM节点的代码如下

    var input = [];    pics = [];    contents = []; ...... inputFrame.onclick =function(e){     var _e,_target;     _e = e ? window.event : null;     if(!_e){       return;    }else{      _target = _e.srcElement || _e.target ;      _index = getIndex(_target);//reflow两次     show(_target,_index);//reflow两次    }  } function show(target,j){  for(var i = 0,i<3;i++){   target[i].style.display = 'none';//reflow  }  target[j].style.display = 'block';//reflow } function getIndex(targer){     if(target){     .....//获取当前的元素索引     return index;     } } 

    如果是通过css预先定义元素的隐藏和显示,通过对父级的className进行操纵,将会把reflow的次数减少到1次

    .pbox .pic,.pbox content{display:none} .J_pbox_0 .pic0,.J_pbox_0 .content0{diplay:block} .J_pbox_1 .pic1,.J_pbox_1 .content1{diplay:block} .J_pbox_2 .pic2,.J_pbox_2 .content2{diplay:block} 
    var input = [],    parentBox = document.getELementById('J_Pbox'); ...... inputFrame.onclick =function(e){     var _e,_target;     if(){      ...     }else{      ...       parentBox.className = 'pbox J_pbox_'+_infex;//reflow一次     } } 

    三、Yahoo军规再度挖掘会怎样?

    在网站性能优化的路上,是不会有终点的,这也是前端工程师永不会妥协的地方。
    想看到更牛P的优化建议么,请移步这里来关注李牧童鞋的分享:

    • 使用combo合并静态资源
    • Bigpipe技术合并动态数据
    • Comet:基于http的服务端推技术
    • 使用DataURI减少图片请求
    • 使用良好的JS,CSS版本管理方案
    • 尝试仅作必要的JS更新
    • 利用本地存储做缓存
    • 关于最小化HTML
    • 进一步讨论Gzip
    • 进一步讨论域名划分
    • 打开keep-alive,重用HTTP连接
    • 使用JSON进行数据交换
    • 保障页面可交互性
    • 缩短最快可交互时间
    • 异步无阻脚本下载
    • 优化内存使用,防止内存泄露
    • 高效的JavaScript
    • 第三方代码性能问题
    • Inline脚本不要与CSS穿插使用
    • 使用高效的CSS选择器
    • 进一步讨论及早Flush
    • 关于视觉和心理学
--------------------------------------------------------------------------------------------------------

After Yahoo 34 Rules -- 网站性能优化新进展 - Presentation Transcript

  1. 网站性能优化WPO(Web Performance Optimization)-- 在YAHOO 34 Rules 之外
    广告技术部:李牧
    2010-7-12
    1
  2. 1前端基础知识VS速度视点
    2
  3. 1.1 网页上一切来自HTTP
    一般情况下,页面上所有的内容都是通过HTTP请求获得
    第一个请求通常是一份(X)HTML文档,也就是浏览器中地址栏的指向.
    3
  4. 1.1 网页上一切来自HTTP
    一般情况下,页面上所有的内容都是通过HTTP请求获得
    第一个请求通常是一份(X)HTML文档,也就是浏览器中地址栏的指向.
    4
    主要的时间花费在http的请求过程中
  5. 1.2 HTML被解析成Dom树
    (X)HTML文档是一份不那么严谨的XML(文本)文档,没有Schema, 有DTD(通常在HTML文本第一行Doctype中定义)
    浏览器按照文档内容自上而下解释运行展现.最终被完整的解析成一颗树(DOM树):
    其余的HTTP请求,除了CSS可以引入背景图和XHR(以后会介绍)之外几乎都是在解析HTML时,由树上的几种特定节点发起的:
    <img>:用来嵌入图片(jpg,png,gif.)
    <iframe>:用来嵌入其他HTML
    <link>:可以用来引入CSS文件,同时CSS内容引入背景图请求
    <script>:可以用来引入JavaScript文件
    <object>和<embed>:通常用来引入Flash文件
    5
  6. 1.2 HTML被解析成Dom树
    (X)HTML文档是一份不那么严谨的XML(文本)文档,没有Schema, 有DTD(通常在HTML文本第一行Doctype中定义)
    浏览器按照文档内容自上而下解释运行展现.最终被完整的解析成一颗树(DOM树):
    其余的HTTP请求,除了CSS可以引入背景图和XHR(以后会介绍)之外几乎都是在解析HTML时,由树上的几种特定节点发起的:
    <img>:用来嵌入图片(jpg,png,gif.)
    <iframe>:用来嵌入其他HTML
    <link>:可以用来引入CSS文件,同时CSS内容引入背景图请求
    <script>:可以用来引入JavaScript文件
    <object>和<embed>:通常用来引入Flash文件
    6
    Dom节点的多少也决定了,HTML解析的速度
    需要发送请求的Dom节点数,决定了HTTP请求个数
    Dom节点的顺序也有讲究.
  7. a.css文件的内容:
    .myTxt {color:red;font-size:50px}
    各种CSS定义驻留在Dom树的属性中或元素节点内.仍然是Dom树的一部分
    1.3 使用CSS定义显示样式
    如何定义字体颜色大小,区块的边框内外变距?
    <span><font size="50" color="red">CSS出现之前</font></span>
    <span style="color:red,font-size:50px">CSS使用Style属性直接定义</span>
    <span class="myTxt">使用Class等多种方式外部定义</span>
    在HTML内定义
    <style>
    .myTxt {color:red;font-size:50px}
    </style>
    通过<link>引入CSS文件,在文件中定义
    <link rel="stylesheet" type="text/css" href="http://a.com/a.css" />
    7
  8. 1.3 使用CSS定义显示样式
    如何定义字体颜色大小,区块的边框内外变距?
    <span><font size="50" color="red">CSS出现之前</font></span>
    <span style="color:red,font-size:50px">CSS使用Style属性直接定义</span>
    <span class="myTxt">使用Class等多种方式外部定义</span>
    在HTML内定义
    <style>
    .myTxt {color:red;font-size:50px}
    </style>
    通过<link>引入CSS文件,在文件中定义
    <link rel="stylesheet" type="text/css" href="http://a.com/a.css" />
    CSS的类意味着:每个类定义的影响范围覆盖所有Dom节点.
    最佳的方式是有展现的在Dom节点出现前定义好CSS.
    另外CSS的背景图等属性也会引入图片HTTP请求.
    a.css文件的内容:
    .myTxt {color:red;font-size:50px}
    各种CSS定义驻留在Dom树的属性中或元素节点内.仍然是Dom树的一部分
    8
  9. 1.4 使用JavaScript语言处理交互
    网页应用是典型的事件驱动系统.JavaScript为交互事件,时间线上的事件定义响应体.来看一个最简单的交互:点击一个按钮,弹出一个警告框.
    <button onclick="alert(1)"></button>
    <button onclick="clk()"></button>
    <script>
    function clk(){
    alert(1);
    }
    </script>
    <script src="http://a.com/a.js"></script>
    a.js文件的内容:
    function clk(){
    alert(1);
    }
    更多原生的鼠标键盘事件类型及事件注册方法详见:关于跨浏览器事件
    JS同样驻留在Dom树的属性中或元素节点内.仍然是Dom树的一部分
    9
  10. 1.4 使用JavaScript语言处理交互
    网页应用是典型的事件驱动系统.JavaScript为交互事件,时间线上的事件定义响应体.来看一个最简单的交互:点击一个按钮,弹出一个警告框.
    <button onclick="alert(1)"></button>
    <button onclick="clk()"></button>
    <script>
    function clk(){
    alert(1);
    }
    </script>
    <script src="http://a.com/a.js"></script>
    a.js文件的内容:
    function clk(){
    alert(1);
    }
    更多原生的鼠标键盘事件类型及事件注册方法详见:关于跨浏览器事件
    JS同样驻留在Dom树的属性中或元素节点内.仍然是Dom树的一部分
    10
    选择合适的时机,合理的方式注册事件
    DomReady而非window.onload,使用事件代理
    保证最快的首次有效交互的时间
  11. 1.5 DHTML--JavaScript改变DOM树
    JavaScript不满足于简单的计算,校验和事件响应.
    浏览器将其内的Dom树为转化JS可以访问和操作的对象.
    由事件或时间线驱动JS响应的方法对Dom树进行修改.称D(Dynamic)HTML
    W3C(万维网联盟)的 Dom Level 1,2&3中定义了3个层次一系列Dom上的操作接口. http://www.w3.org/DOM/DOMTR
    在各种浏览器下Level 1基本都能被正确实现.IE有独特的事件模型.其余浏览器的事件模型符合W3C定义
    11
  12. 1.5 DHTML--JavaScript改变DOM树
    JavaScript不满足于简单的计算,校验和事件响应.
    浏览器将其内的Dom树为转化JS可以访问和操作的对象.
    由事件或时间线驱动JS响应的方法对Dom树进行修改.称D(Dynamic)HTML
    W3C(万维网联盟)的 Dom Level 1,2&3中定义了3个层次一系列Dom上的操作接口. http://www.w3.org/DOM/DOMTR
    在各种浏览器下Level 1基本都能被正确实现.IE有独特的事件模型.其余浏览器的事件模型符合W3C定义
    12
    因为JavaScript可以改变DomTree
    所以HTML在解析Dom时遇到<script>节点时会等待其加载和执行被阻滞
  13. 1.6 AJAX--JavaScript与服务器端交互
    JavaScript已经具有能力完全的改变所在网页的每个细节.
    JavaScript的野心不止于此,如果JS能由事件驱动,从服务器端源源不断的获取新鲜数据,那理论上不再需要第二个页面了.
    网页上一切来自HTTP,获取数据自然需要JavaScript发起HTTP,接收并理解响应.
    于是有了XHR(XmlHttpRequest),首先作为一个ActiveX控件被IE引入.
    为避免潜在的混乱JavaScript仅以单线程运行,但XHR的异步特性使得它独立于JS引擎的线程外工作.
    数据返回前,其他JS,页面上的交互如常运行,而当数据返回时触发事件.
    如今AJAX不单指XHR.所有在不离开当前页面的前提下,由JS主动发起的从服务器端获取JS可解析数据的方案,皆可称AJAX
    13
  14. 1.6 AJAX--JavaScript与服务器端交互
    JavaScript已经具有能力完全的改变所在网页的每个细节.
    JavaScript的野心不止于此,如果JS能由事件驱动,从服务器端源源不断的获取新鲜数据,那理论上不再需要第二个页面了.
    网页上一切来自HTTP,获取数据自然需要JavaScript发起HTTP,接收并理解响应.
    于是有了XHR(XmlHttpRequest),首先作为一个ActiveX控件被IE引入.
    为避免潜在的混乱JavaScript仅以单线程运行,但XHR的异步特性使得它独立于JS引擎的线程外工作.
    数据返回前,其他JS,页面上的交互如常运行,而当数据返回时触发事件.
    如今AJAX不单指XHR.所有在不离开当前页面的前提下,由JS主动发起的从服务器端获取JS可解析数据的方案,皆可称AJAX
    14
    不要使用同步XHR请求,处理好等待状态
    使用JSON数据交换
    适用一切应用于HTTP请求的优化措施
  15. 1.7 Cookie--身份识别与会话保持
    再次回到HTTP本身
    HTTP是一种没有状态协议
    靠存储在客户端的Cookie来标识身份,保持会话
    HTTP分Header和Body两部分
    HTTP的Header分Request和Response两部分
    Request中会带着请求域下的Cookie
    服务端可以通过Response种植Cookie
    Cookie可以种在根域名和所在的子域名下,也可以种植在指定路径下,指定有效时间
    JavaScript可以读写所属HTML页面所在域下的Cookie
    页面http://item.taobao.com/item.html中的JS可以读写item.taobao.com子域名下和taobao.com根域名下cookie
    15
  16. 1.7 Cookie--身份识别与会话保持
    再次回到HTTP本身
    HTTP是一种没有状态协议
    靠存储在客户端的Cookie来标识身份,保持会话
    HTTP分Header和Body两部分
    HTTP的Header分Request和Response两部分
    Request中会带着请求域下的Cookie
    服务端可以通过Response种植Cookie
    Cookie可以种在根域名和所在的子域名下,也可以种植在指定路径下,指定有效时间
    JavaScript可以读写所属HTML页面所在域下的Cookie
    页面http://item.taobao.com/item.html中的JS可以读写item.taobao.com子域名下和taobao.com根域名下cookie
    16
    静态资源(图片,脚本等)放在不含有cookie的域
    最小化cookie大小. HTTP中一个数据包1k,cookie存在于header中,如果过大效率下降很多.
  17. 1.8 小结--七种武器
    HTTP:一切内容通过HTTP请求获得
    HTML:浏览器把HTML解析成Dom树
    CSS:定义HTML的显示样式
    JavaScript:提供计算能力,处理交互事件
    Cookie:网页间,请求间身份识别与会话保持
    DHTML:JavaScript操作Dom树(包括CSS)
    AJAX:JavaScript操纵HTTP(包括Cookie)
    所有前端应用托生于这些基础特性的整合
    Web2.0主要托生于DHTML和AJAX这类JavaScript的能力扩展
    17
  18. 1.8 小结--七种武器
    HTTP:一切内容通过HTTP请求获得
    HTML:浏览器把HTML解析成Dom树
    CSS:定义HTML的显示样式
    JavaScript:提供计算能力,处理交互事件
    Cookie:网页间,请求间身份识别与会话保持
    DHTML:JavaScript操作Dom树(包括CSS)
    AJAX:JavaScript操纵HTTP(包括Cookie)
    所有前端应用托生于这些基础特性的整合
    Web2.0主要托生于DHTML和AJAX这类JavaScript的能力扩展
    18
    来提升武器性能吧!Fast By Default!
    Plan for performance from day 1 !
  19. 1.9 网站性能优化思路
    网页通过HTTP获得,在浏览器解析,那么网页性能优化思路:
    19
  20. 1.9 网站性能优化思路
    网页通过HTTP获得,在浏览器解析,那么网页性能优化思路:
    20
    说法: 80% of the end-user response time is spent on the front-end. 八成时间耗在了前端
    先看看淘宝技术大学的通用教程,稍后回来看应用端开发需要重点关注什么!
  21. 2.淘宝技术大学:<<构建高性能的网站>>-- 小马,玉伯,小凡
    21
    主要介绍14优化军规和20条最佳实践:
    http://developer.yahoo.com/performance/rules.html
  22. 3 如何发现性能相关问题?
    22
  23. 3.1 HTTP数据包嗅探
    记录HTTP请求的形成瀑布图
    -分析HTTP请求间的顺序
    -分析单个请求的内容和各阶段时间(域名解析,建立连接,发送请求,等待响应,接收数据)
    单机版
    HTTPWatch
    Fiddler
    Firebug
    网络版
    基调网络
    AliBench
    23
  24. 3.2 运行时分析(profiling)
    记录网页运行时,JS function的运行耗时或CPU内存使用情况:
    YUI profiler 
    Firebug Profiler 
    Page Speed Activity
    MS Fast
    PageTest
    DynatraceAjax
    24
    相关工具详细介绍 http://www.phpied.com/performance-tools/
  25. 3.3 浏览器内存结构分析(起步阶段)
    检测IE内存泄露工具
    IE Leak Detector a.k.a Drip [ http://www.outofhanwell.com/ieleak/ ]
    分析浏览器中内存结构和GC情况,这方面的研究刚刚起步,当前技术停留在观察浏览器中内存使用痕迹的水平
    IE不开源没有公布相关工具
    Mozilla的相关研究项目http://mozillalabs.com/blog/2009/07/browser-memory-tools-directory/
    25
  26. 3.4 浏览器各种任务性能开销分析(起步阶段)
    分析浏览器运行过程中执行布局,渲染,HTML,调度,DOM,格式化,JS等任务的分别的开销,找到优化关键点
    IE给出的相关统计分享: http://www.slideshare.net/techdude/ie8-whats-coming
    26
  27. 3.5 再次强调优化思路
    27
    更好的借助工具发现问题:
  28. 4 发展中的WPO
    28
  29. 4.1 减少http请求数
    29
  30. 4.1.1 YSlow 35:避免空的Image src
    Image 带有空字符串作为src的属性值将带来额外的请求,有两种形式: 
    HTML:<imgsrc="">
    JavaScript:varimg = new Image();img.src = ""; 
    这两种形式都有一个同样的效果:浏览器发起另外一个请求到节点所属页面的地址
    http://developer.yahoo.com/performance/rules.html#emptysrc
    30
  31. 4.1.2 combo-自动合并脚本和css文件
    combo代表一种服务器端技术,根据客户端HTTP请求的URL,将多个文件合并成一个文件输出.
    多用于JavaScript文件和CSS文件的合并.大量减少HTTP请求数量
    http://cb.alimama.cn/min/?b=libs/yui&f=3.1.0/build/event-custom/event-custom-min.js,3.1.0/build/attribute/attribute-min.js,3.1.0/build/base/base-min.js
    相当于获取了event-custom-min.js,attribute-min.js和base-min.js
    在YUI3由YUI Loader构建的URL确保了多个脚本的正确顺序
    31
  32. 4.1.3 BigPipe—combo动态数据
    Combo的应用面向多个静态资源的请求合并.
    而当一个页面上的动态数据来自多个数据中心时,使用BigPipe技术将动态数据整合在一个HTTP请求中分段输出,达到服务端多数据中心并发,服务端与浏览器端并发的目的.
    现有PHP端的并发技术成熟,比如YAHOO的yfed,只要配合提早flush(),发送chunk的HTTP Response给前端即可.
    BigPipe技术由Facebook引入,适合SNS类应用.
    http://www.facebook.com/note.php?note_id=389414033919
    32
  33. 4.1.4 comet - 基于HTTP的服务端push技术
    33
    服务器端推数据给客户端,保证消息最快速度传递:
    使用有一个Ajax异步请求连接在服务端等待
    使用一个不关闭连接,不断的flush数据(类似bigpipe).
    应用场景:各种WEB IM 和 SNS站点消息通道
    当前问题:
    浏览器到同一域名连接数有限,影响其他同域请求性能
    Web服务器维持长连接消耗过大,存在较严重性能问题
    基于 AJAX 的长轮询(long-polling)方式
    基于 Iframe及 htmlfile的流(streaming)方式
    http://www.ibm.com/developerworks/cn/web/wa-lo-comet/
  34. 4.1.5 DataURI减少图片请求
    网页常用的小图片可以将图片数据使用Base64编码,直接写在文件中.这样可以减少HTTP请求数.
    详见口碑网秦歌的说明:
    http://dancewithnet.com/2009/08/15/data-uri-mhtml/
    应用:淘宝旺旺点灯图片
    34
  35. 4.2 有效利用缓存
    35
  36. 4.2.1 使用良好的JS,CSS版本管理方案
    JS属于静态文件,在我们不需要更新它的时候我们希望它在用户的浏览器端缓存的时间越长时间越好.而我们需要它更新时,往往需要配合JSP,PHP的修改立即生效.
    一般做法,在服务端动态脚本配置资源版本号,通过URL参数区分版本,引入资源,如:
    http://a.com/a.js?v=1.js
    http://a.com/a.css?v=1.css
    红色部分在版本号后面又加了文件后缀是因为IE6早期版本的一个bug.
    通过URL参数区分版本可能受到代理服务器影响,建议:
    http://a.com/v1/a.js
    http://a.com/v1/a.css
    36
  37. 4.2.2 尝试仅做必要的JS更新
    Google的Diffable项目,采用增量更新机制使得JavaScript只下载更新的部分.
    在GoogleMap的项目中,20%-25%的用户可以获得1.2S(25%)的性能提升
    37
    http://www.stevesouders.com/blog/2010/07/09/diffable-only-download-the-deltas/
  38. 4.2.3 利用本地存储,只做必要的更新
    Flash默认为每个域名提供100K的本地存储空间,Flash 的ActionScript3可以将二进制内容存入ShareObject.在新一轮的BannerMaker性能优化中,我们正尝试更好的模块化设计,将编译后的模块存在本地备用.
    另外浏览器也提供其他本地存储技术,也有网站应用这些技术做JS的缓存.
    38
  39. 4.3 减少实际收发数据量
    39
  40. 4.3.1 最小化html
    前面的规则要求我们最小化JS和CSS
    而html也应该最小化,去掉回车和首尾空格.
    但是HTML的压缩存在风险,YAHOO也没有压缩HTML,详见玉伯的说明:
    http://lifesinger.org/blog/2010/05/why-dont-compress-html/
    特定系统中,风险可以规避或者通过测试排除
    40
  41. 4.3.2 进一步讨论Gzip
    虽然包括IE6在内所有主流浏览器都支持Gzip但仍有15%-25%的用户获取到没有压缩的数据.
    原因是在网路上存在代理服务器和一些病毒防火墙.过滤掉了RequestHeader中的接受Gzip信息.
    Gzip检测:发送一段Gzip后的JS代码,如果正确执行种cookie,表明之后可以发回Gzip数据
    建议安全厂商去掉Gzip标识过滤
    另一方面,面向Gzip加密算法,提高压缩比例.比如我们的广告点击加密串,一次取多条广告在加密时,pv级别信息放在一起可以让Gzip后的数据减少3成左右.
    41
  42. 4.4 缩短HTTP请求时间
    42
  43. 4.4.1 进一步讨论域划分
    根源:IE6+HTTP1.1,对于同一个域名只能同时进行2个连接.
    新浏览器扩展了连接限制.但IE6始终大量存在
    而过多的域会导致DNS寻址时间加长.
    使用HTTP1.0可以将连接数扩大到4,但带来了缓存方面的困扰,需要处理好.
    如何确定域划分和具体业务关系很大,比如淘宝将图片分别存放在8个域名中,随着新式浏览器的增多,以及微软在windows update中对IE6的更新,域名会逐步缩减.
    43
  44. 4.4.2 打开keep-alive 重用HTTP连接
    服务打开keep-alive后,连接会保持指定的一段时间才关闭,后续的请求可以重用此连接,节省了HTTP请求中域名解析和建立连接的耗时.
    打开keep-alive会给服务端造成额外的压力, 而且连接时串行的,同一连接同一时间只服务一个HTTP请求. 所以要根据实际情况(页面停留时间)调节keep-alive时间.
    44
  45. 4.5 JavaScript优化
    45
  46. 4.5.1 使用JSON进行数据交换
    JSON在浏览器端解析的效率至少高于XML解析效率1个数量级,如果说AJAX的X代表XML,那么当前我们使用的技术应该称AJAJ
    JSON在新浏览器中内置了生成和解析的方法,在IE6等老式浏览器中,要使用额外的JS方法来解析( http://json.org ),不要使用eval,可能会带来安全问题和性能问题.
    46
  47. 4.5.2 保障网页的可交互性
    JavaScript为单线程语言,在运行时页面会处于锁定状态,任何操作没有响应.
    所以JS进行大量运算时,要使用相关技术保障页面持续可交互
    在所有浏览器中可以实现的方法是,使用setTimeout将大量的循环调用分组执行,每隔一段时间执行一组操作,称Timer.
    针对Ajax的XHR请求,绝对不要使用同步模式,否则浏览器会锁住,知道XHR获得到了服务器端返回数据.因为数据返回依赖网络,时间较长,错误可能较大.
    HTML5规范的 WebWorker为JS提供了多线程机制,线程间使用消息事件联系.异步的XHR也相当于多线程.
    47
  48. 4.5.3 缩短最快可交互时间(TTI)
    最快可交互时间指从浏览器开始访问网页,到网页可以正确处理UI事件交互的时间
    受到挑战的是规则把JS放在底部,因为JS放在底部,JS下载和运行依然需要时间.
    Facebook做法:head加载一个小JS文件,在底部JS加载运行之前,页面事件会请求专门处理这个事件的小段脚本,快速响应
    Yahoo首页实践:缩减初始化载入内容,减少底部脚本,加快DomReady,让重点部分可交互.其余部分延迟加载
    MS正在研发中的工具Doloto:JS中有大部分在初始化时没有调用,通过自动切分出需要的部分.
    48
  49. 4.5.4 异步无阻脚本下载技术
    http://www.stevesouders.com/blog/2009/04/27/loading-scripts-without-blocking/steve的blog介绍了大多数方案
    Script Dom Element:主要使用Dom方法创建Script节点,添加到DomTree中.只要指定了脚本的async属性, 除了Opera浏览器,脚本的下载和执行不会阻滞页面的下载.
    IFramed JS :使用dom方法,动态构建一个没有src的<iframe>节点,通过iframe.contentWindow.document.write().在iframe内加载脚本
    随之而来的问题:通过这种模式 下载多个具有依赖关系的脚本,顺序问题需要解决.
    YUI3:维护脚本之间的依赖关系,通过loader组件顺序的异步加载脚本,结合Combo获取更好的性能
    49
  50. 4.5.5 优化内存使用,防止内存泄露
    delete不再需要的对象
    移除DomTree中不再需要的节点
    移除节点之前先注销节点上绑定的事件
    尽量避免JSObject和DomObject的双向引用(特别需要注意IE下隐式的双向引用,如事件注册)
    注意XHR也可能引入的内存泄露
    http://isaacschlueter.com/2006/10/msie-memory-leaks/
    50
  51. 4.5.6 高效JavaScript的一些Tips
    访问局部变量的速度最快
    优化循环(猜测最易退出处开始)和条件(类似二分法)
    大量字符串链接操作优化(老式浏览器用arr.join(""))
    使用事件代理 http://www.nczonline.net/blog/2009/06/30/event-delegation-in-javascript/
    优化Dom访问 http://www.phpied.com/dom-access-optimization/
    使用4.5.2节的Timer技术,保持交互流畅
    51
  52. 4.5.7 第三方代码相关性能问题
    第三方代码普遍存在性能问题和隐患.主要是脚本阻滞,HTTP过多等.
    Steve最近开展了Performance of 3rd Party Content系列调查,评估美国主要的Mashup公司的埋点代码,并给出改进意见.
    http://www.stevesouders.com/p3pc/
    Google对Analytics做了相关优化,Adsence优化进行中参见Velocity2010:Don't Let Third Parties Slow You Down (http://en.oreilly.com/velocity2010/public/schedule/detail/15412 )
    最近在懒懒的广告代码优化相关分享: 
    http://www.slideshare.net/taobaoued/ss-4888423
    52
  53. 4.6 CSS优化
    53
  54. 4.6.1内联脚本不要与样式表穿插使用
    <link href="1.css"/>
    <script>
    .....
    </script>
    <link href="2.css"/>
    <link href="3.css"/>
    建议将内联脚本放在CSS之上.
    http://www.stevesouders.com/blog/2010/02/15/browser-performance-wishlist/#stylesheet_js
    54
  55. 4.6.2 使用高效的CSS选择器
    从3.4节微软给出的分析可以看出,CSS的消耗在浏览器全部消耗的很大比重.所以有必要优化CSS,使用高效的CSS选择器,达到快速渲染,格式化的目的.
    详情参见Google的文档:
    http://code.google.com/intl/zh-CN/speed/page-speed/docs/rendering.html#UseEfficientCSSSelectors
    55
  56. 4.7 HTML优化
    56
  57. 4.7.1 进一步讨论提早Flush
    57
    通常提早Flush</head>之前的内容
    其实可以Flush更多次,但是要注意<body>中内容的Flush,只有<body>的直接子节点之后Flush,才能达到提前渲染的目的:
    <body>
    <div></div>
    <----Flush 达到预期
    <div></div>
    </body>
    <body>
    <div>
    <div></div>
    <----Flush 失败
    <div></div>
    </div>
    </body>
    目标应用:首页搜索框,Search页广告
    Facebook BigPipe技术网站速度提升一倍:
    http://www.facebook.com/notes/facebook-engineering/making-facebook-2x-faster/307069903919
  58. 4.21 有关视觉和心理学
    58
  59. 4.21 有关视觉和心理学
    有没有感觉快了些?
    59
  60. 5 总结
    60
  61. 5.1 -- 14条优化军规
    1. 尽可能的减少HTTP请求数
    2. 使用CDN
    3. 添加Expires头(或者 Cache-control)
    4. Gzip组件
    5. 把CSS样式放在页面的上方。
    6. 将脚本放在底部(包括内联的)
    7. 避免在CSS中使用Expressions
    8. 将javascript和css独立成外部文件
    9. 减少DNS查询
    10. 压缩JavaScript和CSS文件 (包括内联的)
    11. 避免跳转
    12. 移除重复的脚本
    13. 配置 ETags
    14. 缓存Ajax请求
    61
  62. 5.2 -- 21条最佳实践
    25. 减少访问DOM的次数
    26. 编写聪明的事件处理器代码
    27. 使用 <link> 而不是 @import
    28. 避免使用CSS滤镜
    29. 优化图片
    30. 优化CSS sprites
    31. 不要在HTML中缩放图片
    32. 减小 favicon.ico 体积并缓存
    33. 保证组件不超过25k(mobile)
    34. 将组件拆包分到多个文档中(mobile)
    35. 避免空的Image src
    15. 尽早刷新缓冲区
    16. 用 GET 方法发送Ajax请求
    17. 组件延迟加载
    18. 组件预加载
    19. 减少DOM元素个数
    20. 多域并行下载
    21. 尽量少用iframes
    22. 避免 404 错误
    23. 减小 cookie 的大小
    24. 对某些静态资源减少无谓的cookie传输
    62
  63. 5.3 – 更多
    使用combo合并静态资源
    Bigpipe技术合并动态数据
    Comet:基于http的服务端推技术
    使用DataURI减少图片请求
    使用良好的JS,CSS版本管理方案
    尝试仅作必要的JS更新
    利用本地存储做缓存
    关于最小化HTML
    进一步讨论Gzip
    进一步讨论域名划分
    打开keep-alive,重用HTTP连接
    使用JSON进行数据交换
    保障页面可交互性
    缩短最快可交互时间
    异步无阻脚本下载
    优化内存使用,防止内存泄露
    高效的JavaScript
    第三方代码性能问题
    Inline脚本不要与CSS穿插使用
    使用高效的CSS选择器
    进一步讨论及早Flush
    关于视觉和心理学
    63
  64. 5.4 WPO 相关资源
    书籍: High Performance Web Sites http://book.douban.com/subject/2084131/
    Even Faster Web Sites http://book.douban.com/subject/3686503/
    High Performance JavaScript http://book.douban.com/subject/4183808/
    Website Optimization http://book.douban.com/subject/4124141/
    工具: firebug https://addons.mozilla.org/zh-CN/firefox/addon/1843
    yslowhttps://addons.mozilla.org/zh-CN/firefox/addon/5369
    pagespeedhttp://code.google.com/intl/zh-CN/speed/page-speed/
    firebug&fiddler简明教程: http://www.slideshare.net/taobaoued/ss-3583978
    专题: Yahoo: http://developer.yahoo.com/performance/rules.html
    Google:http://code.google.com/intl/zh-CN/speed/page-speed/docs/rules_intro.html
    Phpied2009:http://www.phpied.com/performance-advent-calendar-2009/
    Velocity2010:http://en.oreilly.com/velocity2010/public/schedule/proceedings
    聚合: http://pipes.yahoo.com/pipes/pipe.run?_id=a6cdaf1d9dbe656ba1f0ab714cc3a08e&_render=rss&howmany=10
    64
  评论这张
 
阅读(702)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017