<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>西红柿爱番茄 &#187; 性能</title>
	<atom:link href="http://www.ilovejs.net/archives/tag/%e6%80%a7%e8%83%bd/feed" rel="self" type="application/rss+xml" />
	<link>http://www.ilovejs.net</link>
	<description>到了创造为主的阶段，不忘继续学习</description>
	<lastBuildDate>Thu, 15 Dec 2011 06:18:39 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>javascript代码性能优化</title>
		<link>http://www.ilovejs.net/archives/878</link>
		<comments>http://www.ilovejs.net/archives/878#comments</comments>
		<pubDate>Fri, 11 Jun 2010 19:35:59 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[性能优化]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[DOM]]></category>
		<category><![CDATA[性能]]></category>
		<category><![CDATA[闭包]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=878</guid>
		<description><![CDATA[在这篇文章叙述的关于Javascript代码优化，其实并没有什么新意，关于这方面的优化，一直都是Nicholas C. Zakas的专利。我在这里将要说的是对当前众多关于Javascript代码优化的方式一个小总结，并尝试去归类各种不同的优化方式，方便于记忆众说纷纭的优化技巧。本人归类的结果如下图所示： Javascript代码优化无非主要围绕：DOM操作、循环、闭包、对象重复出现、对象的声明方式、作用域链、字符串操作、类的声明方式等等。循环、闭包、对象重复出现是从作用域链的角度去优化的；DOM操作主要围绕HTMLCollection、NodeList等来优化；对象的声明方式主要是对象（Object）、数组（Array）、字符串（String）、函数（Function）、正则（RegExp）等内置的对象使用字面量的方式来声明，这个比使用new来实例化相应的对象在性能上要强很多；字符串操作的优化方式主要是通过数组的push和join方法；类的声明方式优化方式主要是分清属性和方法的声明的方式，方法使用prototype的方式来声明；Javascript语言本身的流程操作语句的优化（if、switch、with、eval等等）。 因此，我将Javascript代码优化主要分为六类：DOM“真空”空间、缩短作用域链、字面量声明方式、字符串操作、类声明方式、流程操作语句。下面将逐个叙述： DOM“真空”空间 DOM“真空”空间这个词或许有些迷惑，举个例子就明白了：当使用removeChild将一个DOM元素从DOM树中删除之后，这个DOM元素并没有彻底消失，它就存在于DOM“真空”空间中，可以通过引用重新调用这个元素，并且对它的操作不会影响DOM文档树。 所以很多对DOM的HTMLCollection、NodeList操作的优化，都是利用了这个“真空”空间，先将元素从DOM树中剥离开来，再对这个元素进行一系列的操作之后，最后再通过appendChild或者insertBefore插入原来位置的DOM树中。这样就使得页面的reflow的次数最小化。比如下面优化的例子： [javascript] /** * Remove an element and provide a function that inserts &#8230; <a href="http://www.ilovejs.net/archives/878" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
在这篇文章叙述的关于Javascript代码优化，其实并没有什么新意，关于这方面的优化，一直都是<a  href="http://www.nczonline.net/">Nicholas C. Zakas</a>的专利。我在这里将要说的是对当前众多关于Javascript代码优化的方式一个小总结，并尝试去归类各种不同的优化方式，方便于记忆众说纷纭的优化技巧。本人归类的结果如下图所示：
</p>
<p>
<img src="http://www.ilovejs.net/wp-content/uploads/2010/06/performance.png" title="performance catagroy" width="652" height="162" />
</p>
<p>
Javascript代码优化无非主要围绕：DOM操作、循环、闭包、对象重复出现、对象的声明方式、作用域链、字符串操作、类的声明方式等等。循环、闭包、对象重复出现是从作用域链的角度去优化的；DOM操作主要围绕HTMLCollection、NodeList等来优化；对象的声明方式主要是对象（Object）、数组（Array）、字符串（String）、函数（Function）、正则（RegExp）等内置的对象使用字面量的方式来声明，这个比使用new来实例化相应的对象在性能上要强很多；字符串操作的优化方式主要是通过数组的push和join方法；类的声明方式优化方式主要是分清属性和方法的声明的方式，方法使用prototype的方式来声明；Javascript语言本身的流程操作语句的优化（if、switch、with、eval等等）。
</p>
<p>
因此，我将Javascript代码优化主要分为六类：<em>DOM“真空”空间</em>、<em>缩短作用域链</em>、<em>字面量声明方式</em>、<em>字符串操作</em>、<em>类声明方式</em>、<em>流程操作语句</em>。下面将逐个叙述：
</p>
<p><span id="more-878"></span></p>
<p><strong>DOM“真空”空间</strong><br />
DOM“真空”空间这个词或许有些迷惑，举个例子就明白了：当使用removeChild将一个DOM元素从DOM树中删除之后，这个DOM元素并没有彻底消失，它就存在于DOM“真空”空间中，可以通过引用重新调用这个元素，并且对它的操作不会影响DOM文档树。
</p>
<p>
所以很多对DOM的HTMLCollection、NodeList操作的优化，都是利用了这个“真空”空间，先将元素从DOM树中剥离开来，再对这个元素进行一系列的操作之后，最后再通过appendChild或者insertBefore插入原来位置的DOM树中。这样就使得页面的reflow的次数最小化。比如下面优化的例子：
</p>
<p>[javascript]<br />
/**<br />
 * Remove an element and provide a function that inserts it into its original position<br />
 * @param element {Element} The element to be temporarily removed<br />
 * @return {Function} A function that inserts the element into its original position<br />
 **/<br />
//removeToInsertLater函数的作用是将element从DOM树中删除，保存于DOM“真空”空间里，同时返回一个闭包函数，用于在对element操作之后将其插回原来的位置。<br />
function removeToInsertLater(element) {<br />
  var parentNode = element.parentNode;<br />
  var nextSibling = element.nextSibling;<br />
  parentNode.removeChild(element);<br />
  return function() {<br />
    if (nextSibling) {<br />
      parentNode.insertBefore(element, nextSibling);<br />
    } else {<br />
      parentNode.appendChild(element);<br />
    }<br />
    nextSibling=null; //因为处于闭包中，需要设置为null，断开作用域链，下同。<br />
    parentNode=null;<br />
  };<br />
}<br />
//接下来我们就可以对element进行一系列的操作，最后插回去<br />
function updateAllAnchors(element, anchorClass) {<br />
  var insertFunction = removeToInsertLater(element);<br />
  var anchors = element.getElementsByTagName(&#8216;a&#8217;);<br />
  for (var i = 0, length = anchors.length; i &lt; length; i ++) {<br />
    anchors[i].className = anchorClass;<br />
  }<br />
  insertFunction();<br />
}<br />
[/javascript]</p>
<p>
如果所示，将需要操作的DOM元素先从DOM树中剥离开来，对其进行操作，再安插回去，减少了页面reflow的次数，还有一种方式是将HTMLCollection、NodeList对象转换成数组的形式来进行操作，这都是不错的优化方式，可以应用在很多类似的优化案例中。当然了，对DOM的操作，DOM本身提供的API方法也都存在性能问题，使用nextSibling比childNodes快多了、使用item比使用普通的索引慢多了、不同的循环的方式对操作HTMLCollection、NodeList也都存在不同的性能：《<a  href="http://www.ilovejs.net/archives/248">雷人的优化HTMLCollection对象的循环操作技巧</a>》，这个将会在下面的循环里叙述。
</p>
<p><strong>缩短作用域链</strong><br />
缩短作用域链，说简单点就是尽量使用局部变量来储存外部的对象。对于在循环中重复出现的对象，这个尤其具有优化效果；对于在闭包函数外的对象，当需要在闭包内使用的时候，可以在闭包内声明一个局部变量来储存该对象；还有对DOM元素的length属性、或者在DOM操作的循环中单个DOM元素使用局部变量来储存，也十分具有优化效果。目的就是使得在数据存取的过程中从作用域链中能最快的取出来，而最快的取出来的前提就是需要对象或者变量在作用域链的顶部。经过测试表明：局部变量的存取速度是最快的。所以将作用域外的对象局部引用化，也是不错的优化方式。循环也算是缩短作用域链的一个方面，但是某些方面也不全是，这个跟循环内部的比较和判断有关，具体请浏览《<a  href="http://www.ilovejs.net/archives/180">对循环操作的几种优化</a>》。下面举几个例子：
</p>
<p>[javascript]<br />
//例子一：将NodeList的length属性缓存起来，这样就可以避免每次重新计算length属性，重新查询一遍DOM树。<br />
var d = document.getElementsByTagName(&quot;div&quot;);<br />
for(var i=0, l = d.length; i&lt;l; i++){<br />
   //code here&#8230;<br />
}<br />
//=====================================<br />
//例子二：将每一个DOM元素局部化，因为对每一个DOM元素的操作，都需要在NodeList中去查询这个DOM元素。<br />
var d = document.getElementsByTagName(&quot;div&quot;);<br />
for(var i=0, l = d.length; i&lt;l; i++){<br />
   var item = d[i];<br />
   item.className=&quot;active&quot;;<br />
   item.title = &quot;active item&quot;;<br />
   //&#8230;&#8230;<br />
}<br />
//=====================================<br />
//例子三：储存重复出现的对象或者方法，特别是在循环中。将document.body缓存起来，这样在循环里读取的速度就非常快了。<br />
var b = document.body;<br />
for(var i=0;i&lt;10;i++){<br />
  b.appendChild(document.createTextNode(&quot;some text&quot;));<br />
}<br />
//=====================================<br />
//例子四：对闭包外的对象或者变量在闭包内局部化。<br />
//msg在setTimeout闭包参数的作用域外<br />
function setupAlertTimeout() {<br />
  var msg = &#8216;Message to alert&#8217;;<br />
  window.setTimeout(function() { alert(msg); }, 100);<br />
}<br />
//下面这个更快，将变量声明放到闭包内，使得读取速度更快。<br />
function setupAlertTimeout() {<br />
  window.setTimeout(function() {<br />
    var msg = &#8216;Message to alert&#8217;;<br />
    alert(msg);<br />
  }, 100);<br />
}<br />
//再来个更快的，这下避免使用闭包来作为setTimeout的参数，使得程序运行更快。<br />
function alertMsg() {<br />
  var msg = &#8216;Message to alert&#8217;;<br />
  alert(msg);<br />
}<br />
function setupAlertTimeout() {<br />
  window.setTimeout(alertMsg, 100);<br />
}<br />
[/javascript]</p>
<p>
对于上面例子四中关于闭包的使用，在这里解释一下：闭包非常强大而且使用，但是它也有很多缺陷，比如：是造成很多内存泄漏的罪魁祸首；声明一个闭包比声明一个不是闭包的内部函数更慢，比声明一个静态函数就更慢了。因此得出了上面的结论。
</p>
<p>
还有，对于缩短作用域链的一个更直白的解释例子如下：
</p>
<p>[javascript]<br />
var a = &#8216;a&#8217;;<br />
function createFunctionWithClosure() {<br />
  var b = &#8216;b&#8217;;<br />
  return function () {<br />
    var c = &#8216;c&#8217;;<br />
    a;<br />
    b;<br />
    c;<br />
  };<br />
}<br />
var f = createFunctionWithClosure();<br />
f();<br />
[/javascript]</p>
<p>
如上所示：当函数f调用的时候，读取a比读取b慢，比读取c又更慢。这就是作用域链的存取速度导致的性能问题，在HTMLCollection、NodeList中更甚。
</p>
<p><strong>字面量声明方式</strong><br />
这个字面量的声明方式的优化方式比较简单易懂，就是使用Javascript这门语言所独有的可以使用字面量的形式来声明对象的特点，这些比使用new来实例化响应的内置的对象将消耗更多的性能和时间，而且也不够灵活。比如下面的声明方式：
</p>
<p>[javascript]<br />
var obj = {};<br />
var obj2 = {<br />
        &quot;name&quot;:&quot;supersha&quot;<br />
}<br />
var arr = [];<br />
var arr2 = [1,2];<br />
var reg = /abc/gi;<br />
var fn = function(){<br />
  alert(&quot;传说中的Hello world&quot;);<br />
}<br />
[/javascript]</p>
<p><strong>字符串操作</strong><br />
字符串中的优化已经算是不值得多说了，主要使用数组的push、join方法来时优化。现在来说说使用传统的“+”或者“+=”运算符为啥低效：当使用“+”或者“+=”运算符的时候，内存中先会创建一个变量副本来储存这个连接的结果，之后把结果赋值给“=”号左边的变量或者对象属性，最后销毁这个变量副本，当在循环中通过“+”或者“+=”来连接字符串的时候，就不得不忍受副本变量的创建、赋值、销毁这一连串的操作，如果需要连接的两个字符串比较大的时候，就更难以忍受了。所以，对它的优化，就被无可奈何的提出来了。举个例子：
</p>
<p>[javascript]<br />
//例子一：<br />
var veryLongMessage = [<br />
'This is a long string that due to our strict line length limit of',<br />
' characters per line must be wrapped. ',<br />
'% of engineers dislike this rule. The line length limit is for ',<br />
' style purposes, but we do not want it to have a performance impact.',<br />
' So the question is how should we do the wrapping?'<br />
].join();<br />
//=====================================<br />
//例子二：<br />
var strBuilder = ['First 20 fibonacci numbers:'];<br />
for (var i = 0; i &lt; 20; i++) {<br />
  strBuilder.push(i, &#8216; = &#8216;, fibonacci(i));<br />
}<br />
var fibonacciStr = strBuilder.join(”);<br />
[/javascript]</p>
<p><strong>类声明方式</strong><br />
类声明方式的优化，主要是利用了prototype原型链的优点，使得类在实例化的时候不需要给每一个实例都声明相同名称的方法或者属性，而是通过prototype原型链来声明方法或者属性，使得每一个类的实例都从原型链共享这个方法或者属性（有些不知道怎么表达，暂且这样吧）。比如下面的例子：
</p>
<p>[javascript]<br />
//下面声明类的方式比较糟糕<br />
var Car = function(color,model,owner){<br />
  this.color=color;<br />
  this.model=model;<br />
  this.owner=owner;<br />
  this.setColor=function(c){<br />
    this.color=c;<br />
  }<br />
  //&#8230;.<br />
}<br />
//改进一下下，好多了……<br />
var Car = function(color,model,owner){<br />
  this.color=color;<br />
  this.model=model;<br />
  this.owner=owner;<br />
}<br />
Car.prototype.setColor=function(c){<br />
  this.color=c;<br />
}<br />
[/javascript]</p>
<p>
<strong>流程操作语句</strong><br />
这里所说的流程操作语句主要是if、switch、do while、while、for、try catch，也有with、eval等等。if语句和switch语句之间的衡量是经常会碰到的优化问题：《<a  href="http://www.ilovejs.net/archives/577">对Duff策略优化数组操作的疑虑</a>》；循环的优化在上面已经叙述过了；我相信很多叙述有关Javascript性能的文章都建议避免使用with、eval，甚至是try catch语句，因为catch语句会增加作用域链的深度，造成数据读取速度下降的性能问题，更多的细节可以阅读《<a  href="http://www.ilovejs.net/archives/509">高性能网站建设进阶指南</a>》和<a  href="http://www.nczonline.net/">Nicholas C.Zakas</a>著的《<a  href="http://www.amazon.com/Performance-JavaScript-Faster-Application-Interfaces/dp/059680279X">High Performance JavaScript</a>》中更详细的叙述。
</p>
<p>
<strong>总结：</strong>上面例举了Javascript代码优化的五个基本类别的方式。当然了，Javascript代码优化还远不止上面例子中出现的情况，大到设计模式、Ajax应用，小到还有对if、switch、with、eval等等的优化等等，无处不存在着代码性能优化这些细节问题，但是细化下来，也基本在上面五个类别里了。案例是丰富多彩的，但是本质不变。目的只有一个：<strong>让你的代码跑的更快</strong>。
</p>
<p>
延伸阅读：《<a  href="http://blogs.msdn.com/b/ie/archive/2006/08/28/728654.aspx">IE + JavaScript Performance Recommendations &#8211; Part 1</a>》，《<a  href="http://blogs.msdn.com/b/ie/archive/2006/11/16/ie-javascript-performance-recommendations-part-2-javascript-code-inefficiencies.aspx">IE+JavaScript Performance Recommendations Part 2: JavaScript Code Inefficiencies</a>》，《<a  href="http://blogs.msdn.com/b/ie/archive/2007/01/04/ie-jscript-performance-recommendations-part-3-javascript-code-inefficiencies.aspx">IE+JScript Performance Recommendations Part 3: JavaScript Code Inefficiencies</a>》，《<a  href="http://code.google.com/speed/articles/optimizing-javascript.html">Optimizing JavaScript code</a>》，《<a  href="http://code.google.com/speed/articles/javascript-dom.html">Speeding up JavaScript: Working with the DOM</a>》</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/878/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>@font-face的性能测试</title>
		<link>http://www.ilovejs.net/archives/845</link>
		<comments>http://www.ilovejs.net/archives/845#comments</comments>
		<pubDate>Thu, 10 Jun 2010 03:02:29 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[(X)HTML]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[@font-face]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[性能]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=845</guid>
		<description><![CDATA[对@font-face的作用，也是今晚在看这篇博文《@font-face and performance》的时候，才知道使用它可以自定义显示字体。我想在浏览器中加入@font-face的功能是处于一定的情况的，比如使用特殊的字体来显示页面某部分的字体，从而避免采用图片的方式来显示特定字体。出发点是很好的，但是…… 解析@font-face的机制在不同的浏览器下是不同的。 对于@font-face更多的叙述，在上面提到的那篇博文中有了详细的描述。但是对于它提出的说“IE doesn’t render anything in the page until the font file is done downloading if there &#8230; <a href="http://www.ilovejs.net/archives/845" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
对@font-face的作用，也是今晚在看这篇博文《<a  href="http://www.stevesouders.com/blog/2009/10/13/font-face-and-performance/">@font-face and performance</a>》的时候，才知道使用它可以自定义显示字体。我想在浏览器中加入@font-face的功能是处于一定的情况的，比如使用特殊的字体来显示页面某部分的字体，从而避免采用图片的方式来显示特定字体。出发点是很好的，但是……
</p>
<p>
解析@font-face的机制在不同的浏览器下是不同的。
</p>
<p>
对于@font-face更多的叙述，在上面提到的那篇博文中有了详细的描述。但是对于它提出的说“IE doesn’t render anything in the page until the font file is done downloading if there is a SCRIPT tag above the @font-face declaration.”，说的是当在声明@font-face的前面如果存在script标签的时候，IE下不会渲染任何东西，页面一片空白，直到@font-face指定的字体加载完为止，这点经过测试，确实如此。
</p>
<p>
在声明@font-face的标签之前没有script标签的时候IE下并没有出现阻塞页面渲染的情况，但是如果前面有script标签的时候，不管是否是紧跟这script标签，只要在@font-face标签前面有script标签，就阻塞页面渲染：《<a href="http://www.ilovejs.net/lab/fontface/fontface.html">没有script标签</a>》，《<a  href="http://www.ilovejs.net/lab/fontface/fontface-script.html">紧跟script标签</a>》，《<a  href="http://www.ilovejs.net/lab/fontface/fontface-nodirec-script.html">不紧跟script标签</a>》。
</p>
<p>
同时，我测试了@font-face是否会阻塞页面其他资源加载，测试发现并没有这个问题：《<a  href="http://www.ilovejs.net/lab/fontface/fontface2.html">是否阻塞资源加载的测试</a>》，而且在字体加载下来之前，忙指示器会一直处于等待状态。下面是各种浏览器对@font-face的测试比较结果，结果分为三类：IE，Firefox、Opera，Safari、Chrome。
</p>
<ol>
<li>在Firefox、Opera中，并不会阻塞页面其他资源的加载，也不会影响页面渲染，而且在字体加载下来之前，对想应用该字体的内容会使用默认的字体显示，直到字体加载下来之后再渲染为指定的字体。因此，这两个浏览器测试效果最佳。</li>
<li>在Safari、Chrome中，并不会阻塞页面其他资源加载，也不会影响页面渲染，但是在字体加载下来之前，对应用该字体的内容将会首先空白显示，但是内容尺寸是存在的，直到字体加载完成，才渲染字体样式。</li>
<li>在IE下就分不同的情况了，如上所述，前面是否有script标签的情况。</li>
</ol>
<p>
对于@font-face的杯具的性能问题，如果没有必要，就尽量避免使用。如果一定要使用的话，可以使用使用lazy load的方式来加载，例如博文中给出的例子：
</p>
<p>[javascript]<br />
function lazyload() {<br />
  var sRule1 =<br />
	&quot;@font-face {&quot; +<br />
	&quot;  font-family: &#8216;Yanone&#8217;;&quot; +<br />
	&quot;  src: url(&#8216;/bin/resource.cgi?type=font&amp;sleep=6&#8242;);&quot; +<br />
	&quot;  src: local(&#8216;Yanone&#8217;), &quot; +<br />
        &quot;url(&#8216;/bin/resource.cgi?type=font&amp;sleep=6&#8242;) &quot; +<br />
        &quot;format(&#8216;truetype&#8217;);&quot; +<br />
        &quot;}&quot;;</p>
<p>  var style1 = document.styleSheets[0];<br />
  if ( &quot;function&quot; === typeof(style1.insertRule) ) {<br />
        // Firefox, Safari, Chrome<br />
	style1.insertRule(sRule1, 0);<br />
  }else if ( &quot;string&quot; === typeof(style1.cssText) ) {<br />
	// IE<br />
	style1.cssText = sRule1;<br />
  }<br />
}<br />
[/javascript]</p>
<p>
将上面的lazyload函数添加到页面的onload事件中去执行，这样就保证了页面的正常渲染并且实现特定字体样式的功能：《<a href="http://www.stevesouders.com/tests/font-face/lazyload.php">lazy load测试</a>》。这个主要是解决IE下@font-face前面有script标签的问题，在其他浏览器下显示的时候，也都还是会在应用该字体的内容中产生空白闪烁、或者是默认字体和指定字体之间的切换闪烁。也都还是在一定程度上影响了用户体验，感觉有些不爽。“<em>Tradeoff is anywhere!!</em>”
</p>
<p>
上面的三个测试都是使用内联CSS的方式，考虑到使用外联CSS样式表的情况，又对此做了一番测试，发现了不同的状况：
</p>
<ol>
<li>当link放在head时，IE6、8（没有IE7，测试不了）都是死心眼，偏执要阻塞整个页面的加载，在字体下载下来之前整个页面一片空白，其他浏览器跟内联CSS一样的显示：《<a href="http://www.ilovejs.net/lab/fontface/fontface-extend-css-head.html">外联CSS测试（在head内）</a>》。</li>
<li>当link放到body中时，IE8还是阻塞整个页面的渲染，可是IE6就不同了，IE6会阻塞整个页面样式的渲染，但是不会阻塞link前面的内容的显示，而是阻塞了其后面的内容的显示了，直到字体加载下来之后才开始渲染页面样式和显示link后面的内容。其他浏览器跟内联CSS一样的显示：<br />
《<a href="http://www.ilovejs.net/lab/fontface/fontface-extend-css-body.html">外联CSS测试（在body最底部）</a>》，《<a href="http://www.ilovejs.net/lab/fontface/fontface-extend-css-middle.html">外联CSS测试（在body中部）</a>》</li>
<li>当link前面带有script标签的时候，因为外联在head头部的时候在IE各版本都阻塞了，所以这个条件link在页面的任何位置都无所谓，主要测试link前面带有script标签，那就把link放在body中来测试。这下IE6也杯具了，阻塞了整个页面的渲染，IE8照常阻止整个页面渲染，其他浏览器同上。《<a href="http://www.ilovejs.net/lab/fontface/fontface-extend-css-middle-script.html">外联CSS测试（在body中部），前跟script标签</a>》，将link放到body最底部也一样阻塞整个页面的渲染：《<a href="http://www.ilovejs.net/lab/fontface/fontface-extend-css-body-script.html">外联CSS测试（在body最底部），前跟script标签</a>》，其他浏览器同上。</li>
</ol>
<p>
对于页面中同时有script和link、style标签是很正常的事情，但是当样式中有@font-face的时候，情况就复杂了。更多的测试条件大家可以自行测试。有错误的地方，请不吝留言交流。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/845/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>小译“Best Practices for Speeding Up Your Web Site”</title>
		<link>http://www.ilovejs.net/archives/187</link>
		<comments>http://www.ilovejs.net/archives/187#comments</comments>
		<pubDate>Wed, 06 Jan 2010 09:21:10 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[性能优化]]></category>
		<category><![CDATA[优化]]></category>
		<category><![CDATA[性能]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=187</guid>
		<description><![CDATA[昨天接触到这篇文章《Best Practices for Speeding Up Your Web Site》，觉得太经典了，自己不由自主的想要翻译过来，鉴于本人的英语水平，只翻译了其中的某些条目，有错误在所难免。更多的还是推荐浏览原文。 首先的说明的是：优化页面显示速度，就是不管HTML内容多与少，都要尽量在最快的速度显示出来，这就是Front-end engineers首要明确的意图。所以下面所提及的优化方式，都是从这一目的出发的。下面的翻译的一些条目： 1.最小化HTTP request请求。因为一个页面显示所花费的时间很多都是花费在scripts，stylesheets，images，flashs等等，这些都会通过http request来加载，这些大概占用了页面加载时间的70%-80%，因此，减少HTTP request能很大的优化页面的加载速度。 2.使用第三方的代理服务器来加载scripts，stylesheets等等，这能降低本主服务器的负载，比如google ajax api提供的目前流行的js库：jquery，extjs，prototype，MooTools等等 3.在头部声明cache的expire。在用户第一次view页面的时候会加载全部的内容，包括html以及scripts，stylesheets，images等等，设置了cache的expire一方面能使得用户在下次view页面的时候能从缓存里读取一些数据，减少了HTTP Request的请求数，加快页面的显示。不过这要看用户view页面的回头率是否频繁。设置了cache的expire也要适当。一方面能加快加载速度，另一方面也有助于在cache的expire过期的时候使得用户获得页面的最新数据信息。 4.使用压缩技术（Gzip &#8230; <a href="http://www.ilovejs.net/archives/187" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
昨天接触到这篇文章《<a href="http://developer.yahoo.com/performance/rules.html">Best Practices for Speeding Up Your Web Site</a>》，觉得太经典了，自己不由自主的想要翻译过来，鉴于本人的英语水平，只翻译了其中的某些条目，有错误在所难免。更多的还是推荐浏览原文。
</p>
<p>
首先的说明的是：优化页面显示速度，就是不管HTML内容多与少，都要尽量在最快的速度显示出来，这就是Front-end engineers首要明确的意图。所以下面所提及的优化方式，都是从这一目的出发的。下面的翻译的一些条目：
</p>
<p>
1.最小化HTTP request请求。因为一个页面显示所花费的时间很多都是花费在scripts，stylesheets，images，flashs等等，这些都会通过http request来加载，这些大概占用了页面加载时间的70%-80%，因此，减少HTTP request能很大的优化页面的加载速度。
</p>
<p>
2.使用第三方的代理服务器来加载scripts，stylesheets等等，这能降低本主服务器的负载，比如google ajax api提供的目前流行的js库：jquery，extjs，prototype，MooTools等等
</p>
<p>
3.在头部声明cache的expire。在用户第一次view页面的时候会加载全部的内容，包括html以及scripts，stylesheets，images等等，设置了cache的expire一方面能使得用户在下次view页面的时候能从缓存里读取一些数据，减少了HTTP Request的请求数，加快页面的显示。不过这要看用户view页面的回头率是否频繁。设置了cache的expire也要适当。一方面能加快加载速度，另一方面也有助于在cache的expire过期的时候使得用户获得页面的最新数据信息。
</p>
<p>
4.使用压缩技术（Gzip Components）。原理就是将scripts，stylesheet，images，flash等等压缩为一个zip文件，之后把这个zip文件链接进页面中来减少http request回调来加快页面的加载速度。通过摄自豪HTTP header的Accept-Encoding为gzip, deflate，之后在Response header里设置Content-Encoding: gzip来解压压缩包的文件，就可以将这些文件导入到页面的相应的部分。不过，如果页面中的Component比较少或者也是相对于非常小的话，还是不建议使用这种方法，还是使用普通的通过各自的连入方式加载Component。
</p>
<p>
5.将全部的Stylesheets放到head里来加载。Yahoo测试了这种方式证明了这一方式确实能加快页面的加载速度，“This is because putting stylesheets in the HEAD allows the page to render progressively.”。
</p>
<p>
6.将Scripts放置到Bottom(底部）。我们都知道，通过script标签引入文件会阻止下面的HTML内容的加载，等待script加载文件完成才加载下面的内容。因此：HTTP/1.1 specification建议在每一个主机名下不要超过两个Component同时下载。还有一点要说明的是：当script正在加载的时候，浏览器机会停止一切其他的加载项，甚至不同的主机下的文件都不会加载（通过iframe加载的内容）。<br />
但是有时候有很难将scripts都放到bottom里，这里的主要问题就是通过document.write来添加页面内容以及作用域问题。因此，就需要使用其他的方式来解决这样的问题了。<br />
这里有一种建议方案：就是使用deferred scripts（延迟执行scripts），通过使用script标签的defer属性来延迟执行不包含document.write的js代码。defer的机制就是先加载好scripts，之后在DOM加载完成之后，执行js代码（defer的延迟要比window.onload早），因此使用defer会在DOM加载完成，window.onload之前执行js代码。但是defer属性目前只有IE支持，Firefox等浏览器不支持，要通过检查DOM是否加载完成这样的方式来解决。因此，如果一个script可以defer延迟的话，同样也就可以把它放置到bottom里，这样就能加快页面的加载（显示）速度。
</p>
<p>
7.避免使用css的Expressions。CSS的expression虽然很强大，能动态修改css的样式规则，只有IE能识别expression属性。<br />
但是，致命的问题在于：它执行的非常的频繁，页面的一个render，resize和scroll，以及用户的一些简单的鼠标操作，比如：移动鼠标等等都会触发expression的重复执行。一个测试表明：在页面内移动鼠标就非常容易的产生超过10000次的执行次数。这将是难以想象的耗费性能。<br />
一种解决办法就是一次执行expression之后，就给css 样式指定确切的值，而不在需要依赖expression。
</p>
<p>
8.通过外联的方式来加载外部的Javascript和css到页面里。在第一条里我们谈到减少Http request请求来加载Component，而这里又提倡使用外联的方式来加载scripts、Stylesheet等等Component，不是冲突了吗？这里来解释一下：如果不是通过外联的方式来加载文件，这样在每次加载页面的时候，都需要去加载内联的Javascript和css内容，这就使得HTML容量变大了。而使用外联的方式的好处在于浏览器会缓存这些文件，第二次加载页面的时候就会在缓存里读取这些文件（如果缓存里还没有清除的话），这使得HTML页面“变小”了，不是更快加载HTML了吗。从这一角度来考虑，视具体情况而定，来综合考虑上面所提到的几种优化方案。
</p>
<p>
9.压缩Javascript和css代码。压缩代码就是清除掉一些不需要的characters，减小代码文件的大小，从而加快加载。可以通过使用<a href="http://crockford.com/javascript/jsmin">JSMin</a>或者<a href="http://developer.yahoo.com/yui/compressor/">YUI Compressor</a>，还有<a href="http://dean.edwards.name/packer/">Jspacker</a>等等压缩工具。压缩代码的范围可以很广泛，包括独立的js或者css文件，当然也可以是内联的js或者css代码（google就使用了这种方式），也可以是上面所说的通过压缩Components联入页面的各个js或者css文件。
</p>
<p>
10.删除重复的Scripts Component。有时候如果不加注意，可能就会重复加载了同一个script联入文件，比如通过script联入，之后在某种形式下使用php的insertScript又联入了同一个文件，这都是有可能的。这将会有哪些不合理呢：一个是花费Http request的数目而且还会影响浏览器的缓存方面的问题，使得script重复加载。
</p>
<p><span id="more-187"></span></p>
<p>
11.使Ajax可以缓存。Ajax在我们看来是用于跟服务器异步传输数据的，每一步都需要新的数据。当然这是我们都计较长涉及到的，但是某些情况下，Ajax缓存同样重要，说个比较简单的例子：比如用户通过搜索（当然这个搜索是通过Ajax形式）来观看一些书籍的内容的时候，因为书籍内容是分章节分页面的，而且内容都基本会保持不变，当用户搜索同一文章而且Last modified没有修改的情况下，就可以从缓存里返回上次的搜索内容，而不必重新搜索，从后台传输数据了。
</p>
<p>
12.在Ajax Requests中使用GET方式。Yahoo！Mail团队发现当使用XMLHttpRequest的时候，使用POST方式在浏览器会执行两部操作：先发送headers信息，之后发送data数据。而GET方式只需要“take one TCP packet”。但是IE中对于URL长度的限制在2K之内，所以data超过2K的话还是需要使用POST的方式。
</p>
<p>
13.延迟加载一些Components。我的理解是这样的：对于页面中一些不需要在页面中即刻需要显示出来的效果或者内容的时候，可以延迟加载这些内容。比如Javascript中的拖动以及一些暂时隐藏的内容等等，这些都可以在页面其他的内容加载完之后再去加载它。这就不会影响整体的页面的显示速度了。
</p>
<p>
14.预先加载Components。这似乎跟上面的延迟加载Components有冲突，但是不尽然。这里的情况是这样的：在浏览器空闲的时候（比如：onload之后）预先加载Components（images，scripts，Stylesheets），这样在用户浏览其他页面的时候，当其他页面中使用到了这些Components的时候，就可以直接在Cache里读取，而无需重新加载。
</p>
<p>
15.减少DOM Elements。这就涉及到HTML页面的架构问题了，可以想象，当一个页面中存在500或者5000个DOM Elements的时候，在页面加载的时候，DOM渲染速度，将会是一个怎样的区别。所以，这也要求设计HTML页面架构的时候能保持简洁和语意化。使得DOM Elements尽量的少，提高DOM渲染速度。
</p>
<p>
16.减少页面中的iframes数量。我们知道，iframe可以将其他页面嵌入到当前页面中。但是懂得它的运行方式将会非常有用。<br  /><br />
好处是：是一个安全的沙箱；可以平行的下载scripts；减缓第三方内容的显示比如广告等。<br />
坏处是：花费时间来加载页面内容如果链接到一个空页面或者一个不存在的页面；打断了页面的onload进程。
</p>
<p>
17.避免404错误的出现。404错误是没有找到指定URL的页面，出现这个错误页面的时候也是很耗费时间的，而且它很糟的一个方面是当用户等待了几秒甚至更长的时间来等待页面显示，最后显示出来的是404错误，用户体验度明显下降了。还有一个很糟的方面是如果通过script外联的Javascript文件找不到，这一方面会打断页面的加载进程，另一方面也使得页面的功能逻辑缺失。
</p>
<p>
18.减小Cookie的大小。HTTP cookies在存储一下私人信息等方面，但是Cookie是通过HTTP headers在服务器端和客户端之间交换的。所以就非常有必要去尽量减小cookie的大小，使得用户的response time的影响最小化。<br />
在“<a href="http://yuiblog.com/blog/2007/03/01/performance-research-part-3/">When the cookie Crumbles</a>”一篇文章里详细分析了Cookie，它指出：<br />
a.去除一下不需要的cookies。<br />
b.尽量使得cookie最小化以简短用户的response time。<br />
c.适当的设置cookie的expire过期时间。<br />
d.在设置cookie的domain的时候要非常小心，使得其他的sub-domains不会受影响。
</p>
<p>
19.要明智的设置Event Handlers。有时候页面感觉反应迟钝或者缓慢，一个方面是因为页面中的event handlers在DOM Elements里设置的太多了，事件通过冒泡或者捕获等等导致事件发生的太频繁。要根据实际情况，明智的设置Event heandlers。
</p>
<p>
20.外联css文件选择
<link>而不是@import。上面我们提到了将css外联文件都放置到head部分里，这样可以加快页面加载速度。对于@import语法，在IE下等同于使用
<link>外联css文件并放置到bottom里了，所以不推荐使用@import的方式。
</p>
<p>
21.避免使用Filters。我们知道，IE下css的滤镜可以通过filter属性来设置很多华丽的效果。但问题是filter一方面打断页面的渲染和当图片在加载的时候冻结了浏览器；另一方面也是增加了内存的消耗。<br />
所以，应该避免使用filter滤镜，使用更好的PNG8来代替，如果非要使用，请使用_filter，使得用IE7的用户能有一个更好的用户体验。
</p>
<p>
22.合理的使用各种格式的image。图片有gif，png，jpg等这三种是网页比较常用的三种格式，但是知道这三种格式的图片特性，合理的使用，也是非常有必要的。<br />
gif一般文件都比较小，但是只有256种颜色。<br />
png最大的一个特点就是支持透明度。<br />
jpg以它的高清晰度而为人所用。
</p>
<p>
23.使favicon.ico尽量小并可以缓存。很多网站都设置了favicon.ico一个小图片在浏览器的URL地址栏里显示。这非常好。但是favicon.ico跟cookie以及其他的Components一样都是需要Http request加载的，所以尽量保持它能被浏览到（避免出现404错误）和可以缓存，就显得十分有必要了。下面是关于favicon.ico的两项建议：使得favicon.ico保持在1K以下；在header里合理设置Expire过期时间。
</p>
<p>
24.保持全部的Components的大小在25K以下。这个限制的原因是由于iPhone的机制：如果超过25K，它就不会缓存页面的Components。因此为了页面跟iPhone兼容，合理减小Components也是有必要的。
</p>
<p>
上面的翻译是根据自己的英语水平以及自己对于它们的一点见解，有错误的地方在所难免，本人都苦于没有中文版的介绍。所以干脆自己在浏览过后小译一番，也方便自己以后对它的理解吧。但是本人还是推荐对这方面感兴趣的朋友去阅读原文。
</p>
<p>更多内容请浏览：《<a href="http://developer.yahoo.com/performance/rules.html">Best Practices for Speeding Up Your Web Site</a>》，《<a href="http://yuiblog.com/blog/2007/03/01/performance-research-part-3/">Part 3: When the Cookie Crumbles</a>》，《<a href="http://yuiblog.com/blog/2007/01/04/performance-research-part-2/">Part 2: Browser Cache Usage – Exposed!</a>》，《<a href="http://support.microsoft.com/?id=922733">http://support.microsoft.com/?id=922733</a>》，《<a href="http://developer.yahoo.com/yui/imageloader/">YUI 2: ImageLoader</a>》，《<a href="http://developer.yahoo.com/yui/get/">YUI 2: Get Utility</a>》，《<a href="http://yuiblog.com/blog/2007/04/11/performance-research-part-4/">Part 4: Maximizing Parallel Downloads in the Carpool Lane</a>》，《<a href="http://yuiblog.com/blog/2007/12/20/video-lecomte/">High Performance Ajax Applications</a>》，《<a href="http://yuiblog.com/blog/2008/02/06/iphone-cacheability/">Part 5: iPhone Cacheability – Making it Stick</a>》</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/187/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

