<?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/category/%e6%80%a7%e8%83%bd%e4%bc%98%e5%8c%96/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>浏览器对charset的处理方式</title>
		<link>http://www.ilovejs.net/archives/1526</link>
		<comments>http://www.ilovejs.net/archives/1526#comments</comments>
		<pubDate>Mon, 28 Mar 2011 14:40:56 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[性能优化]]></category>
		<category><![CDATA[Charset]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1526</guid>
		<description><![CDATA[charset的作用：告诉浏览器，对于服务器端返回来的HTML文件流用何种编码进行解码，从而进行HTML的解析操作。 有三个地方可以设置charset，而且它们的优先级是有顺序的：1、response header；2、HTML文档中的meta；3、浏览器默认的charset声明。那么它们的优先级是如何的呢？ 首先要了解浏览器处理charset的策略：浏览器首先会在服务器返回的response header头中检查是否有charset声明，如果没有，就接着检查HTML head部分的meta标签，是否有声明charset，如果还没有，那么就使用浏览器默认的charset方式进行解码文档流。 在response header头中声明好了charset，那么浏览器在第一时间接收到HTML数据包的时候，就会以这个charset编码进行解码HTML文件流，这种情况下是最快的方式；如果response header头中没找到，那么浏览器会delay解析HTML文档，检查1KB以内的HTML内容是否会包含有charset声明的meta标签。如果还找不到，那么就使用浏览器默认的charset声明进行解码HTML页面，但是这时，已经delay了一些时间了。 如果处理的适当，那么这个delay时间是完全可以避免的，使得HTML页面可以尽可能快的让浏览器使用显示声明的编码进行解码文件流。那就是：在服务端设置好请求内容的charset编码；始终在页面中meta标签内声明charset，当然了，content-type也是十分有必要的。]]></description>
			<content:encoded><![CDATA[<p>
charset的作用：告诉浏览器，对于服务器端返回来的HTML文件流用何种编码进行解码，从而进行HTML的解析操作。
</p>
<p>
有三个地方可以设置charset，而且它们的优先级是有顺序的：1、response header；2、HTML文档中的meta；3、浏览器默认的charset声明。那么它们的优先级是如何的呢？
</p>
<p>
首先要了解浏览器处理charset的策略：浏览器首先会在服务器返回的response header头中检查是否有charset声明，如果没有，就接着检查HTML head部分的meta标签，是否有声明charset，如果还没有，那么就使用浏览器默认的charset方式进行解码文档流。
</p>
<p>
在response header头中声明好了charset，那么浏览器在第一时间接收到HTML数据包的时候，就会以这个charset编码进行解码HTML文件流，这种情况下是最快的方式；如果response header头中没找到，那么浏览器会delay解析HTML文档，检查1KB以内的HTML内容是否会包含有charset声明的meta标签。如果还找不到，那么就使用浏览器默认的charset声明进行解码HTML页面，但是这时，已经delay了一些时间了。
</p>
<p>
如果处理的适当，那么这个delay时间是完全可以避免的，使得HTML页面可以尽可能快的让浏览器使用显示声明的编码进行解码文件流。那就是：在服务端设置好请求内容的charset编码；始终在页面中meta标签内声明charset，当然了，content-type也是十分有必要的。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1526/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>权衡之变</title>
		<link>http://www.ilovejs.net/archives/1511</link>
		<comments>http://www.ilovejs.net/archives/1511#comments</comments>
		<pubDate>Sun, 20 Mar 2011 09:05:57 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[代码设计]]></category>
		<category><![CDATA[性能优化]]></category>
		<category><![CDATA[模块化]]></category>
		<category><![CDATA[重构]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1511</guid>
		<description><![CDATA[《重构&#8211;改善既有代码的设计》这本书是去年买的了，利用晚上空闲时间看了大部分的内容，包括一些重构的技巧、良好代码的特点、代码可读性和提高语义化等。这本书改变了很多我之前所持有的观念，包括代码性能、模块化设计、结构样式逻辑分离等的思维。下面粗略的罗列几点目前自己从这本书中所理解到的其中一些知识： 重构本来就不是一件应该特别拨出时间做的事情，重构应该随时随地进行。 第一次做某件事情时只管去做；第二次做类似的事情会产生反感，但无论如何还是可以去做；第三次再做类似的事，你就应该重构。 &#8212;&#8212;“事不过三，三则重构。” 只要将相对独立的代码从大型函数中提炼出来，就可以大大提高代码的可读性。 不单只让函数能够功能单一的执行，同时也需要让一个类也只需要明确的做一件事情，或者只是对各个功能的集合（代理、命名空间）。 在该函数最常引用的类中建立一个有着类似行为的新函数，将旧函数变成一个单纯的委托函数，或者将旧函数完全移除。根据这个函数与哪个对象的交流比较多，决定将函数移动的位置。 抽象函数可以是多重的，将可复用的代码尽量的抽象它，在抽象后的函数中，又需要对函数进行进一步的思考，是否功能还可以更加的细化，让功能函数为更多的其他函数、对象、类所复用。距离组织一个库来说：core大部分只提供核心类（核心对象）的扩展、继承机制、底层内置功能的扩充、封装机制、兼容性判断机制、对象版本管理机制等，这就算是一个core最细化的抽象。 一个类应该是一个清楚的抽象，处理一些明确的责任。 “封装”意味着每个对象都应该尽可能少了解系统的其他部分，如此一来，一旦发生变化，需要了解这一变化的对象和函数就会比较少，这会使变化比较容易进行。 有几个原因造成我喜欢简短而命名良好的函数：首先，如果每个函数的粒度都很小，那么函数被复用的机会就更大；其次，这会使高层函数读起来就像一系列注释；再次，如果函数都是细粒度，那么函数的覆写也会更容易些。 在函数的命名上，长度不是问题，关键在于函数名称和函数本体之间的语义距离。 创造一个新函数，根据这个函数的意图来对它命名（以它“做什么”来命名，而不是以它“怎么做”命名），但是如果你想不出一个更有意义的名称，那就别动。 如果在提炼的函数中需要一些原来旧函数中的局部变量数据，那么就将这些局部变量数据通过参数的形式传递过去。 当一个函数有参数的时候，在函数体里就尽量不要去修改参数的值，不管是通过值还是引用传递进来的，除非有另外特定的目的。 将函数细粒化为一个个功能单一的函数，再调用这些函数，这必然造成了性能上更多的耗费，但是这跟后期的维护、以及代码的可读性等等相比，或许还是值得这么做的。 永远不要认为你写的代码只是自己看的而已，要想到新来的人接手你的这些代码的时候，他们看你的代码，是否能够很愉快的接受并理清整个思路。不要把这个维护代码的痛苦留给接手你的人。不管你是通过更多的注释还是重构代码的方式来解决代码的可维护性的问题，都要想到这一点。 在分解一个函数的时候，我的思路是：需求是什么 &#8211;> 需求的功能有哪些 &#8230; <a href="http://www.ilovejs.net/archives/1511" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
《<a href="http://product.dangdang.com/product.aspx?product_id=20801315">重构&#8211;改善既有代码的设计</a>》这本书是去年买的了，利用晚上空闲时间看了大部分的内容，包括一些重构的技巧、良好代码的特点、代码可读性和提高语义化等。这本书改变了很多我之前所持有的观念，包括代码性能、模块化设计、结构样式逻辑分离等的思维。下面粗略的罗列几点目前自己从这本书中所理解到的其中一些知识：
</p>
<blockquote><p>重构本来就不是一件应该特别拨出时间做的事情，重构应该随时随地进行。<br />
第一次做某件事情时只管去做；第二次做类似的事情会产生反感，但无论如何还是可以去做；第三次再做类似的事，你就应该重构。 &#8212;&#8212;“事不过三，三则重构。”
</p></blockquote>
<p><span id="more-1511"></span></p>
<ol>
<li>只要将相对独立的代码从大型函数中提炼出来，就可以大大提高代码的可读性。</li>
<li>不单只让函数能够功能单一的执行，同时也需要让一个类也只需要明确的做一件事情，或者只是对各个功能的集合（代理、命名空间）。</li>
<li>在该函数最常引用的类中建立一个有着类似行为的新函数，将旧函数变成一个单纯的委托函数，或者将旧函数完全移除。根据这个函数与哪个对象的交流比较多，决定将函数移动的位置。</li>
<li>抽象函数可以是多重的，将可复用的代码尽量的抽象它，在抽象后的函数中，又需要对函数进行进一步的思考，是否功能还可以更加的细化，让功能函数为更多的其他函数、对象、类所复用。距离组织一个库来说：core大部分只提供核心类（核心对象）的扩展、继承机制、底层内置功能的扩充、封装机制、兼容性判断机制、对象版本管理机制等，这就算是一个core最细化的抽象。</li>
<li>一个类应该是一个清楚的抽象，处理一些明确的责任。</li>
<li>“封装”意味着每个对象都应该尽可能少了解系统的其他部分，如此一来，一旦发生变化，需要了解这一变化的对象和函数就会比较少，这会使变化比较容易进行。</li>
<li>有几个原因造成我喜欢简短而命名良好的函数：首先，如果每个函数的粒度都很小，那么函数被复用的机会就更大；其次，这会使高层函数读起来就像一系列注释；再次，如果函数都是细粒度，那么函数的覆写也会更容易些。<br />
在函数的命名上，长度不是问题，关键在于函数名称和函数本体之间的语义距离。<br />
创造一个新函数，根据这个函数的意图来对它命名（以它“做什么”来命名，而不是以它“怎么做”命名），但是如果你想不出一个更有意义的名称，那就别动。<br />
如果在提炼的函数中需要一些原来旧函数中的局部变量数据，那么就将这些局部变量数据通过参数的形式传递过去。
</li>
<li>当一个函数有参数的时候，在函数体里就尽量不要去修改参数的值，不管是通过值还是引用传递进来的，除非有另外特定的目的。</li>
<li>将函数细粒化为一个个功能单一的函数，再调用这些函数，这必然造成了性能上更多的耗费，但是这跟后期的维护、以及代码的可读性等等相比，或许还是值得这么做的。</li>
<li>永远不要认为你写的代码只是自己看的而已，要想到新来的人接手你的这些代码的时候，他们看你的代码，是否能够很愉快的接受并理清整个思路。不要把这个维护代码的痛苦留给接手你的人。不管你是通过更多的注释还是重构代码的方式来解决代码的可维护性的问题，都要想到这一点。</li>
<li>在分解一个函数的时候，我的思路是：需求是什么 &#8211;> 需求的功能有哪些 &#8211;> 团队开发方式是如何的 &#8211;> 在当前功能点下，罗列函数层级的功能点，并根据这些功能点进行整合，即是高内聚，低耦合。之后逐一组建函数。<br />
明白需求是什么，这个是做开发的最先需要了解清楚的，这点无可厚非；在这个需求下面，需要实现一些什么功能，这个是需要根据需求来分析出来的，之后的就是根据自己团队的代码开发模式，并逐步将需求的功能点，细化到代码层级的功能点，将功能抽象出来，提高代码的可复用度。
</li>
</ol>
<p>
自己之前所遵守的高性能、微小代码量、满脑子模块化、保持结构样式逻辑高度分离等的思维，再次进行了权衡的颠覆。对于代码，性能重要，但是人也能很容易的看懂这也重要。一个项目，到底是开发新功能的需求大，还是维护、优化项目的需求更多，这个就需要在高速开发和提高代码的可读性和较少维护成本进行权衡。
</p>
<p>
使用工具进行页面拼装的方式，固然可以提高开发效率，这对于一些促销页面开发、或者是有PM、运营所自定义页面来说，确实有必要。但是这些都是辅助页面，核心产品才是主要关注点，核心产品一般不会轻易的推倒重来，而是不断的进行优化、功能升级、新功能上线等。为此，对于开发者来说，除了代码能够给电脑读，还能很好的给其他开发者读懂，这个有必要。在性能和代码量上或许可以做个权衡，也或者可以从其他方面进行优化来弥补这方面的损失。
</p>
<p>
模块化，有时候真的很少用到，除非是大站点，从整体架构考虑，提高功能的聚合度和整体统一。在一些细小项目、功能开发中，用到更多的还是借助于统一的库，进行二次的功能开发，封装为适合该项目、功能的功能函数集。就如上面《重构》书中所述，当这个功能为几个项目、功能所使用的时候，那么就有必要抽象出来，作为一个模块。但是，对于模块，从现阶段来说，它已经不是跟以前一样，只是一个js文件，它所要负责是它的功能范围内的HTML、CSS、JS，对于页面来说，我无需关心这个模块有啥，我只需要调用这个模块的接口，加载这个模块，那么我的页面中就有了这个模块最基本的功能，再复杂点，就是提供给模块进行扩展的接口，在模块的基础上，进行自定义结构、样式、逻辑。
</p>
<p>
所以，对于模块化，要区分好Moudle，Utilities，功能函数的差别。Util只是对功能逻辑的封装，加载这个js文件，就可以直接使用它所提供的逻辑方法，它并不涉及到样式、结构，只是一个逻辑。功能函数更多的是存在于页面中的，如果使用度够高，那么就会成为Util的一部分。功能函数更多的是在已有的库的基础上进行的二次封装、抽象，提供给其他的功能直接调用。将页面中都会用到的功能进行抽取，作为一个独立的功能函数，通过参数来体现功能的差异。
</p>
<p>
在结构、样式、逻辑上，这个并没有完全的分离的界限，很多时候都需要看功能的具体需求，不能完全要求分离结构和逻辑，就使得在逻辑方面需要做很多的动态创建结构的工作。这就需要权衡：如何使用正确的HTML标签，标签能否提供一些辅助的信息，来简化逻辑的操作和代码量。适合在标签上能做的事情，就让标签来提供。“各司其职”的折中是互相辅助。
</p>
<p>
想得有点多了，需要慢慢学习和实践~~</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1511/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>压缩HTML的意义</title>
		<link>http://www.ilovejs.net/archives/1475</link>
		<comments>http://www.ilovejs.net/archives/1475#comments</comments>
		<pubDate>Tue, 18 Jan 2011 01:45:53 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[(X)HTML]]></category>
		<category><![CDATA[性能优化]]></category>
		<category><![CDATA[HTML压缩]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1475</guid>
		<description><![CDATA[对于压缩HTML的好与坏、利与弊，网上也已经谈论的很多，自己也搜集了一下，毕竟自己最近也在做这样的一个工具来压缩HTML代码，提出一下自己的见解以及一些设想。 支持不压缩HTML的原因有这样的一些考虑：去掉换行、多个空白之后可能会对样式有影响；pre标签形式压缩之后会失去原有的意义；IE条件注释不能够删除；只是压缩空白和注释收益不大，特别是在gzip压缩之后；压缩了代码，看源码不方便；性价比低，付出的技术成本跟收到的效果不成正比&#8230;。原因很多哎，所以造成了大部分的站点对于HTML都是未压缩的状态发布了。为什么不压缩 HTML 这几天思前想后，HTML压缩的意义在哪里？ 如果纯粹是压缩注释、空格、换行，并且在开启Gzip压缩的情况下，那么这些确实很有限制，如果没有gzip压缩呢？开启了gzip压缩，但是被一些防火墙软件、杀毒软件把请求头的Accept-Encoding给短路了呢？那么这样的话，页面的HTML代码估计要大20%了，如果这20%是对于一个日均pv大的站点，可以估量这个宽带的花费，收益是很明显的，Who’s not getting gzip?。 我们可以开启Gzip，但是不能够完全相信用户的浏览器得到的都是gzip压缩后的代码，客户端的环境是复杂的，如果没有gzip压缩的话，页面的代码量跟压缩HTML之后的代码量，需要一个具体的数据来权衡。 空白、注释这些在浏览器是会去解析的，解析为空白节点、注释节点，多个空格需要解析为一个空格节点，这些都是会耗费浏览器的资源的。我相信，在普遍的浏览器解析HTML文档流的时候，一行的解析总比解析几行来的快，就像解析CSS规则一样，解析一条规则比解析几条规则总来的快。一点点猜测HTML的解析原理。。。 但是又不能够一股脑门的去压缩全部的HTML代码，或者使用手工的方式去压缩，这个成本确实会很大。如果只是压缩空格、注释，这个收益也确实会很小。这就应该使用一个工具来最大化的压缩HTML代码，使用词法分析的方式，对于一些浏览器默认的HTML属性，但是在开发过程中又显示声明了，那么这些就是可以清除的；更疯狂的可以对属性的单双引号去除（不过这个对属性值带有单双引号可能会造成问题，需要衡量）；一些不必要的meta标签的声明的缩减或者删除，比如： &#60;meta name=”robots” content=”index&#124;follow”&#62; 替换为&#60;meta name=”robots” content=”all”&#62; 小日本对这两个meta标签看的很重： &#60;meta http-equiv=”Content-Style-Type” &#8230; <a href="http://www.ilovejs.net/archives/1475" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
对于压缩HTML的好与坏、利与弊，网上也已经谈论的很多，自己也搜集了一下，毕竟自己最近也在做这样的一个工具来压缩HTML代码，提出一下自己的见解以及一些设想。
</p>
<p>
支持不压缩HTML的原因有这样的一些考虑：去掉换行、多个空白之后可能会对样式有影响；pre标签形式压缩之后会失去原有的意义；IE条件注释不能够删除；只是压缩空白和注释收益不大，特别是在gzip压缩之后；压缩了代码，看源码不方便；性价比低，付出的技术成本跟收到的效果不成正比&#8230;。原因很多哎，所以造成了大部分的站点对于HTML都是未压缩的状态发布了。<a  href="http://lifesinger.org/blog/2010/05/why-dont-compress-html/">为什么不压缩 HTML</a>
</p>
<p>
这几天思前想后，HTML压缩的意义在哪里？
</p>
<p><span id="more-1475"></span></p>
<p>
如果纯粹是压缩注释、空格、换行，并且在开启Gzip压缩的情况下，那么这些确实很有限制，如果没有gzip压缩呢？开启了gzip压缩，但是被一些防火墙软件、杀毒软件把请求头的Accept-Encoding给短路了呢？那么这样的话，页面的HTML代码估计要大20%了，如果这20%是对于一个日均pv大的站点，可以估量这个宽带的花费，收益是很明显的，<a  href="http://www.stevesouders.com/blog/2009/11/11/whos-not-getting-gzip/">Who’s not getting gzip?</a>。
</p>
<p>
我们可以开启Gzip，但是不能够完全相信用户的浏览器得到的都是gzip压缩后的代码，客户端的环境是复杂的，如果没有gzip压缩的话，页面的代码量跟压缩HTML之后的代码量，需要一个具体的数据来权衡。
</p>
<p>
空白、注释这些在浏览器是会去解析的，解析为空白节点、注释节点，多个空格需要解析为一个空格节点，这些都是会耗费浏览器的资源的。我相信，在普遍的浏览器解析HTML文档流的时候，一行的解析总比解析几行来的快，就像解析CSS规则一样，解析一条规则比解析几条规则总来的快。一点点猜测HTML的解析原理。。。
</p>
<p>
但是又不能够一股脑门的去压缩全部的HTML代码，或者使用手工的方式去压缩，这个成本确实会很大。如果只是压缩空格、注释，这个收益也确实会很小。这就应该使用一个工具来最大化的压缩HTML代码，使用词法分析的方式，对于一些浏览器默认的HTML属性，但是在开发过程中又显示声明了，那么这些就是可以清除的；更疯狂的可以对属性的单双引号去除（不过这个对属性值带有单双引号可能会造成问题，需要衡量）；一些不必要的meta标签的声明的缩减或者删除，比如：<br />
&lt;meta name=”robots” content=”index|follow”&gt;<br />
替换为&lt;meta name=”robots” content=”all”&gt;<br />
小日本对这两个meta标签看的很重：<br />
&lt;meta http-equiv=”Content-Style-Type” content=”text/css”&gt;<br />
&lt;meta http-equiv=”Content-Script-Type” content=”text/javascript”&gt;<br />
对于咱们，可能是完全没有必要的；<br />
对于行内样式规则的最后一个分号进行清理等等，嵌入到真正的代码中进行优化，效果还是可观的。
</p>
<p>
而对于压缩的方式，可以支持标识一定范围内的标签进行压缩，而不是一股脑门的对整个HTML文档进行压缩，这样就可以重复的自定义HTML压缩，而对于有pre、压缩之后会出现样式错误（这纯粹是利用空格来展示样式的错误方式导致的，可以从技术上去尽量避免这个事情，因为很容易留下个暗坑让人踩）等问题。
</p>
<p>
压缩之后，对浏览器解析HTML的性能、代码量、减少宽带上收益会更大，性价比也高。
</p>
<p>
但是，这个需要工具，替人干活的工具的出现。。。。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1475/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Perl编译程序升级</title>
		<link>http://www.ilovejs.net/archives/1390</link>
		<comments>http://www.ilovejs.net/archives/1390#comments</comments>
		<pubDate>Sun, 02 Jan 2011 08:28:18 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[性能优化]]></category>
		<category><![CDATA[前端开发工具]]></category>
		<category><![CDATA[编译工具]]></category>
		<category><![CDATA[自动化]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1390</guid>
		<description><![CDATA[经过几个晚上的一点点升级，将之前搞的perl编译脚本进行了重构，并添加了一些功能，包括文件嵌套编译、添加对html文件的简单压缩、添加Google Compiler的压缩模式、修改了文件输出的方式等等。（具体的教程，可以查看：自动化工具提高工作效率中的描述） 在perl文件的头部，添加了几个配置项： $yui_compressor_path：YUI compressor 的jar文件的路径（建议是本地的绝对路径） $google_compiler_path：Google Compiler的jar文件的路径（建议是本地的绝对路径） $compress_type：所使用的压缩方式，值可以为：yui/gc。 $compilation_level：Google Compiler压缩的级别，值可以为：SIMPLE_OPTIMIZATIONS/ADVANCED_OPTIMIZATIONS/WHITESPACE_ONLY $output_dir：编译后的文件的输出目录（建议是跟当前需要编译的文件同一目录下） 建议是在每一个开发目录下配置一个build.pl文件，那么就可以对在当前的目录下进行开发，最后build编译。如今编译的文件都会保存在当前目录下的output文件夹里，文件名不变，可以直接使用编译好的文件进行测试、发布。 如下图所示的嵌套包含示意图，理论上可以无限级的嵌套，压缩： 可以对当前级声明compress:true进行压缩，嵌套之后，在output文件夹中会有中间产物页面产生，但是对于最终页面是没影响的。这样，就可以将几个页面中通用的部分抽取出来，统一管理。 最新的build程序：build_1_0_3_linux.rar，build_1_0_3_win.rar。]]></description>
			<content:encoded><![CDATA[<p>
经过几个晚上的一点点升级，将之前搞的perl编译脚本进行了重构，并添加了一些功能，包括文件嵌套编译、添加对html文件的简单压缩、添加Google Compiler的压缩模式、修改了文件输出的方式等等。（具体的教程，可以查看：<a  href="http://www.ilovejs.net/archives/1348">自动化工具提高工作效率</a>中的描述）
</p>
<p>
在perl文件的头部，添加了几个配置项：<br />
$yui_compressor_path：YUI compressor 的jar文件的路径（建议是本地的绝对路径）<br />
$google_compiler_path：Google Compiler的jar文件的路径（建议是本地的绝对路径）<br />
$compress_type：所使用的压缩方式，值可以为：yui/gc。<br />
$compilation_level：Google Compiler压缩的级别，值可以为：SIMPLE_OPTIMIZATIONS/ADVANCED_OPTIMIZATIONS/WHITESPACE_ONLY<br />
$output_dir：编译后的文件的输出目录（建议是跟当前需要编译的文件同一目录下）
</p>
<p>
建议是在每一个开发目录下配置一个build.pl文件，那么就可以对在当前的目录下进行开发，最后build编译。如今编译的文件都会保存在当前目录下的output文件夹里，文件名不变，可以直接使用编译好的文件进行测试、发布。
</p>
<p>
如下图所示的嵌套包含示意图，理论上可以无限级的嵌套，压缩：
</p>
<p>
<img src="http://www.ilovejs.net/wp-content/uploads/2011/01/perl1.png" alt="" title="文件嵌套" width="520" height="290" class="alignnone size-full wp-image-1397" />
</p>
<p>
可以对当前级声明compress:true进行压缩，嵌套之后，在output文件夹中会有中间产物页面产生，但是对于最终页面是没影响的。这样，<strong>就可以将几个页面中通用的部分抽取出来，统一管理</strong>。
</p>
<p>
最新的build程序：<a  href="/download/build_1_0_3_linux.rar">build_1_0_3_linux.rar</a>，<a  href="/download/build_1_0_3_win.rar">build_1_0_3_win.rar</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1390/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>自动化工具提高工作效率</title>
		<link>http://www.ilovejs.net/archives/1348</link>
		<comments>http://www.ilovejs.net/archives/1348#comments</comments>
		<pubDate>Sun, 26 Dec 2010 15:30:43 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[性能优化]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[开发流程]]></category>
		<category><![CDATA[自动化]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1348</guid>
		<description><![CDATA[这些日子一直为几个开发流程上的纯手工问题苦恼，对于linux的命令来回折腾又有点不是很熟练（Shell脚本也可以集合命令跑编译），为了将自己的劳动力解放出来，干脆写个Perl小脚本来解决当下问题得了： js、css代码本地自动化压缩的问题。 文件使用include的方式，无所不包。解决了在一个页面中代码过多，滚动调试页面的烦恼很纠结，上下滚动，烦。 既然是包含，那么就需要提供可以包含任意的内容：css、js、html（嵌套包含），并且提供内联或者外联的方式。 为了将自己从开发流程的手工劳动中解放出来，还是得自力更生，开发自己的自动化工具。所以这个礼拜两天就开发了一个小脚本，纯粹边学边用。想象下面的一段编译前的代码： [html] &#60;!doctype html&#62; &#60;html&#62; &#60;head&#62; &#60;meta charset=&#34;utf-8&#34;&#62; &#60;meta http-equiv=&#34;X-UA-Compatible&#34; content=&#34;IE=Edge&#34;&#62; &#60;meta http-equiv=&#34;X-Frame-Options&#34; content=&#34;DENY&#34; /&#62; &#60;title&#62;Template&#60;/title&#62; &#8230; <a href="http://www.ilovejs.net/archives/1348" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
这些日子一直为几个开发流程上的纯手工问题苦恼，对于linux的命令来回折腾又有点不是很熟练（Shell脚本也可以集合命令跑编译），为了将自己的劳动力解放出来，干脆写个Perl小脚本来解决当下问题得了：
</p>
<ol>
<li>js、css代码本地自动化压缩的问题。</li>
<li>文件使用include的方式，无所不包。解决了在一个页面中代码过多，滚动调试页面的烦恼很纠结，上下滚动，烦。</li>
<li>既然是包含，那么就需要提供可以包含任意的内容：css、js、html（嵌套包含），并且提供内联或者外联的方式。</li>
</ol>
<p>
为了将自己从开发流程的手工劳动中解放出来，还是得自力更生，开发自己的自动化工具。所以这个礼拜两天就开发了一个小脚本，纯粹边学边用。想象下面的一段编译前的代码：
</p>
<p>[html]<br />
&lt;!doctype html&gt;<br />
&lt;html&gt;<br />
&lt;head&gt;<br />
&lt;meta charset=&quot;utf-8&quot;&gt;<br />
&lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=Edge&quot;&gt;<br />
&lt;meta http-equiv=&quot;X-Frame-Options&quot; content=&quot;DENY&quot; /&gt;<br />
&lt;title&gt;Template&lt;/title&gt;<br />
&lt;script&gt;<br />
/* inline script */<br />
&lt;/script&gt;<br />
&lt;!&#8211;&lt;link rel=&quot;stylesheet&quot; href=&quot;/wp-content/c/style.css&quot;&gt;&#8211;&gt;</p>
<p>&lt;include{file:style.css|style2.css|style3.css,compress:true,extend:true}&gt;</p>
<p>&lt;/head&gt;<br />
&lt;body&gt;</p>
<p>&lt;include{file:t.html}&gt;</p>
<p>&lt;!&#8211; &lt;script src=&quot;yui-debug.js&quot;&gt;&lt;/script&gt; &#8211;&gt;<br />
&lt;include{file:common.js|form.js|cate.js,compress:true,extend:false}&gt;<br />
&lt;/body&gt;<br />
&lt;/html&gt;<br />
[/html]</p>
<p>
这个页面中包含了三个include的内容：CSS、HTML、JS，因此，这个页面看起来会非常的简单，而且在开发期可以将HTML、CSS、JS独立开来开发，而且在HTML、CSS、JS中还可以再细分，使用include包含其他的文件，细分开来，进行颗粒化。上面的页面在脚本编译过后，会是下面的样子：
</p>
<p>
<img src="/wp-content/uploads/build.png">
</p>
<p>
那么现在，我可以通过在include语句中配置属性，可以自动化实现压缩、外联、内联、包含等功能，最后跑一下脚本，就可以整合成一个整体的页面，就可以进行放心的测试了，而不用担心在未压缩代码的情况测试的不准确。
</p>
<p>
下面来介绍一下这个小脚本的用法以及配置环境：
</p>
<ol>
<li>安装一个Perl脚本的运行环境，建议是<a  href="http://www.activestate.com/activeperl" target="_blank">ActivePerl</a></li>
<li>因为涉及到yui compressor压缩，所以还得安装一下java：<a  href="http://www.java.com/zh_CN/" target="_blank">http://www.java.com/zh_CN/</a></li>
<li>上面的环境安装好之后，那么就从YUI上把最新版的YUI Compressor给下载下来吧，记住是jar文件：<a  href="http://developer.yahoo.com/yui/compressor/" target="_blank">http://developer.yahoo.com/yui/compressor/</a></li>
<li>一切外在的环境搭建好之后，那么下面介绍下脚本的语法和目前所拥有的功能：
<p>目前，include的语法是：</p>
<p>[javascript]<br />
&lt;include{file:file1[|file2|...],compress:true|false,extend:true|false}&gt;<br />
[/javascript]</p>
<p>
功能是比较简单、直接的，就是提供了合并文件、压缩、内联还是外联的方式整合页面。而现在所需要的，就是一个Perl脚本来编译这个include语句。属性说明：</p>
<ul>
<li>@file：可以包含几个文件，几个文件之间用”|”分隔，文件的类型要相同。</li>
<li>@compress：true|false。是否压缩代码，这里使用的是yui compressor压缩。</li>
<li>@extend：true|false。是外联还是内联的方式，声明这个属性主要是为了区别css、js和html之间的差别，不声明这个属性，那么就直接在当前的include位置插入内容；声明了之后，true表示外联（link、script），false是内联的方式（style、script）。</li>
<ul>
</li>
</ol>
<p><strong>编译命令语法</strong>：</p>
<ul>
<li>在windows下，可以使用CMD，命令是：<strong style="color:red">perl build.pl file1 file2 [...]</strong>；file1、file2&#8230;表示要编译的文件列表。</li>
<li>在Linux下，可以使用Shell，命令是：<strong style="color:red">./build.pl file1 file2 [...]</strong>；file1、file2&#8230;表示要编译的文件列表。同时，还要使用命令chmod a+x build.pl来让build.pl具有可执行的权限。</li>
</ul>
<p>
还有一点，就是在build.pl文件中要标明yui compressor jar文件的位置，在build.pl文件的开头处$yui_compressor_path这个变量来写明jar文件在本地电脑的path，建议是将jar文件放到一个比较固定的位置，在build.pl使用绝对位置来引用这个jar文件，那么之后你的build.pl可以放到本地的任何地方执行并可以压缩代码了（建议将build.pl放到跟需要编译的文件同目录下，生成的一些文件也会跟编译的文件同一目录下）。
</p>
<p>
当前这个脚本还比较简单，适应本人工作中的需求，后期随着工作方式的改变以及进一步的升级，功能会逐步的完善，这个完善的路还是比较长，也或许以后会编写其它形式的工具来代替。它的主要特点是本地自动化编译、压缩代码、而且使用简单。最主要的是，你可以将几个页面通用的内容、功能和样式提取出来，进行单一的维护，多处生效。有兴趣的可以试玩一下，能够提高你的工作效率就更好了。
</p>
<p>
提供build.pl脚本的下载地址：<a  href="/download/build-windows.rar">build-windows.rar</a> <a  href="/download/build-linux.rar">build-linux.rar</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1348/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>[翻译] 十条js代码优化原则</title>
		<link>http://www.ilovejs.net/archives/1336</link>
		<comments>http://www.ilovejs.net/archives/1336#comments</comments>
		<pubDate>Wed, 08 Dec 2010 14:29:30 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[性能优化]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1336</guid>
		<description><![CDATA[网上看到的一篇文章，说的是js脚本优化的十条细则，看了下文章，优化的知识都很普通，搞前端的人都知道，罗列一下，增强记忆吧： 定义局部变量。对于当前函数作用域内，如果需要使用这个作用域外部的一些变量，那么就尽量使用局部变量储存外部的变量吧，特别是对于嵌套多级的作用域查询，这个耗时也是比较严重的。还有就是获取DOM节点、NodeList、HTMLCollection等等，可以将NodeList、HTMLCollection转化为数组的形式进行操作，减少DOM即时更新所造成的性能消耗。 不要使用with语句。with语句会在当前作用域下面增加作用域链，造成当前作用域下面变量的遍历性能消耗更大。 对于闭包的使用，节省点，不要太过多了。闭包就是提供一个所谓的“封闭式”的作用域，只允许向包含它向别人访问，而不允许别人访问它。但是声明一个闭包的代价比声明普通的函数的代价是要更高的，况且还有IE下内存泄漏的危险。 获取字面量对象的属性和数组的项比获取变量更慢。如果你要获取一些数据的时候，使用变量比用数组、字面量对象的索引来访问来的更快。在循环中经常会需要访问数据，使用变量存储一下，来的更快。 在数组中不要嵌套的过深。js中没有二维数组的概念，但是可以自己编写一个二维数组，并且可以无限的嵌套下去，json很经常就是这么干的。但是嵌套的越深，访问数组中的项就更难了，级数和性能消耗成正比的。 少用for-in循环。众所周知，for-in用于遍历对象的属性和方法，它所要消耗比for、while、do-while更多的性能。在for-in循环中，对于每一个循环，javasript需要创建一个函数来处理每一个循环，这就带来这么两个性能问题：函数创建、销毁的过程；这个函数在创建之后，又会储存它直接上级的作用域的活动对象。 对于循环，合并控制循环的语句，以及控制变量变化方式。在一个控制循环的语句中，比如循环结束条件、索引的递增等等，如果可以优化这些操作，那么对于整个循环的性能是有帮助的。比如对于结束循环条件：for(var i =0;i]]></description>
			<content:encoded><![CDATA[<p>
网上看到的一篇文章，说的是js脚本优化的十条细则，看了下文章，优化的知识都很普通，搞前端的人都知道，罗列一下，增强记忆吧：
</p>
<ol>
<li>定义局部变量。对于当前函数作用域内，如果需要使用这个作用域外部的一些变量，那么就尽量使用局部变量储存外部的变量吧，特别是对于嵌套多级的作用域查询，这个耗时也是比较严重的。还有就是获取DOM节点、NodeList、HTMLCollection等等，可以将NodeList、HTMLCollection转化为数组的形式进行操作，减少DOM即时更新所造成的性能消耗。</li>
<li>不要使用with语句。with语句会在当前作用域下面增加作用域链，造成当前作用域下面变量的遍历性能消耗更大。</li>
<li>对于闭包的使用，节省点，不要太过多了。闭包就是提供一个所谓的“封闭式”的作用域，只允许向包含它向别人访问，而不允许别人访问它。但是声明一个闭包的代价比声明普通的函数的代价是要更高的，况且还有IE下内存泄漏的危险。</li>
<li>获取字面量对象的属性和数组的项比获取变量更慢。如果你要获取一些数据的时候，使用变量比用数组、字面量对象的索引来访问来的更快。在循环中经常会需要访问数据，使用变量存储一下，来的更快。</li>
<li>在数组中不要嵌套的过深。js中没有二维数组的概念，但是可以自己编写一个二维数组，并且可以无限的嵌套下去，json很经常就是这么干的。但是嵌套的越深，访问数组中的项就更难了，级数和性能消耗成正比的。</li>
<li>少用for-in循环。众所周知，for-in用于遍历对象的属性和方法，它所要消耗比for、while、do-while更多的性能。在for-in循环中，对于每一个循环，javasript需要创建一个函数来处理每一个循环，这就带来这么两个性能问题：函数创建、销毁的过程；这个函数在创建之后，又会储存它直接上级的作用域的活动对象。</li>
<li>对于循环，合并控制循环的语句，以及控制变量变化方式。在一个控制循环的语句中，比如循环结束条件、索引的递增等等，如果可以优化这些操作，那么对于整个循环的性能是有帮助的。比如对于结束循环条件：for(var i =0;i<10;i++)，每次循环的时候，都要执行：#1 i是否存在；#2 i是否 < 10；#3 i++。优化一下，使用while或者do-while：var i = 9;do { ...} while(i--)，那么这样之后，每一个循环需要执行的操作：#1 i--；#2 i是否为true。这样就对循环条件的执行步骤进行了简化。</li>
<li>对于HTMLCollection，尽量定义一个数组来储存它。这样可以避免DOM即时更新所造成的影响。</li>
<li>在操作DOM节点的时候，尽量让它飘了吧。让DOM元素脱离document之后再对它进行操作，最后再重新插回document中，最小化reflow（改变了DOM元素布局性的相关的属性之后就会触发，比如：height、width等）、repaint（改变了DOM元素显示上的变化就会触发，比如：background、color等）所造成的影响。</li>
<li>改变DOM节点样式的时候，尽量改变DOM元素的class而不是style属性。原因你懂的……</li>
</ol>
<p>
规则是死的，不能泛用；规则又是活的，看你是否活学活用，用到思维里去，在你编写代码的时候就可以随手写出符合这些规则的代码。
</p>
<p>英文原文：<a  href="http://jonraasch.com/blog/10-javascript-performance-boosting-tips-from-nicholas-zakas">http://jonraasch.com/blog/10-javascript-performance-boosting-tips-from-nicholas-zakas</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1336/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>说点javascript的加载、解析、执行对浏览器渲染的影响</title>
		<link>http://www.ilovejs.net/archives/1322</link>
		<comments>http://www.ilovejs.net/archives/1322#comments</comments>
		<pubDate>Thu, 18 Nov 2010 16:08:49 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[性能优化]]></category>
		<category><![CDATA[动态加载]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1322</guid>
		<description><![CDATA[javascript的加载方式，总得来说是在页面上使用script来声明，以及动态的加载这些方式，而动态的加载，在很多js库中都能够很好的去处理，从而不至于阻塞其他资源的加载，并与其并行加载下来。这样的动态异步的加载方式罗列起来有：Ajax的方式、DOM Element Insert、Iframe、document.write、defer等等。这些都能够很好的处理js在加载的时候不会阻塞资源加载的问题，但是，js的执行仍然会阻塞浏览器的渲染。或许这是不得不需要付出的代价，有没有一些方式去缓解js在执行的时候对浏览器的渲染所造成的延迟的影响呢？ 首先，让我们从UI Thread、UI Queue、UI Upate的角度去分析整个页面和javascript的行为。浏览器在加载HTML到最后呈现出来的这段过程，整个就是一个UI Thread进程，这个UI Thread里是一个浏览器的响应队列，而UI Queue则是浏览器的行为队列，包括UI Update，javascript的执行行为。那么在页面加载的过程中，UI Queue里面就储存了UI Update、js加载、js解析、js执行等。不管是UI Thread，还是UI Queue，都是按照顺序来的。页面在刚开始未遇到js的加载和执行的时候，是UI Update的一个过程，一旦遇到js，就会等待js的加载、解析、执行完毕之后，接着又开始UI Update，如此这样的一个相应顺序。 那么当js的加载是异步了之后呢，这个时候，js的加载和解析不会在UI Queue的执行队列里，而是等到js加载、解析完毕，一到执行的时候，就添加到UI Queue队列中，从而阻塞了UI &#8230; <a href="http://www.ilovejs.net/archives/1322" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
javascript的加载方式，总得来说是在页面上使用script来声明，以及动态的加载这些方式，而动态的加载，在很多js库中都能够很好的去处理，从而不至于阻塞其他资源的加载，并与其并行加载下来。这样的动态异步的加载方式罗列起来有：Ajax的方式、DOM Element Insert、Iframe、document.write、defer等等。这些都能够很好的处理js在加载的时候不会阻塞资源加载的问题，但是，js的执行仍然会阻塞浏览器的渲染。或许这是不得不需要付出的代价，有没有一些方式去缓解js在执行的时候对浏览器的渲染所造成的延迟的影响呢？
</p>
<p>
首先，让我们从UI Thread、UI Queue、UI Upate的角度去分析整个页面和javascript的行为。浏览器在加载HTML到最后呈现出来的这段过程，整个就是一个UI Thread进程，这个UI Thread里是一个浏览器的响应队列，而UI Queue则是浏览器的行为队列，包括UI Update，javascript的执行行为。那么在页面加载的过程中，UI Queue里面就储存了UI Update、js加载、js解析、js执行等。不管是UI Thread，还是UI Queue，都是按照顺序来的。页面在刚开始未遇到js的加载和执行的时候，是UI Update的一个过程，一旦遇到js，就会等待js的加载、解析、执行完毕之后，接着又开始UI Update，如此这样的一个相应顺序。
</p>
<p><span id="more-1322"></span></p>
<p>
那么当js的加载是异步了之后呢，这个时候，js的加载和解析不会在UI Queue的执行队列里，而是等到js加载、解析完毕，一到执行的时候，就添加到UI Queue队列中，从而阻塞了UI Queue中后面的行为（UI Update）的执行。这就是开头所说的在js的执行期总会阻塞页面的渲染，也就是UI Update。但是这个动态加载的方式跟普通在页面中使用script标签来加载的时候的优势是：将js的加载、解析的行为独立出来，不影响浏览器的UI Update，知道执行期才阻塞。这就很多的程度上加快了页面的渲染和展现。
</p>
<p>
再来说说defer和async属性，defer属性最开始是为IE所实现的，现代的浏览器也都逐渐实现了，那么它的工作原理是什么呢。它的作用跟上面动态加载的优势很相同，js的加载和解析是独立的，但是有一点不同的是：使用了defer属性之后，js代码会等到DOM加载完成的时候才执行，这个时候就又更大限度的让浏览器尽快的UI Update部分完成，让js的执行对浏览器的渲染所造成的影响更小化。那么async呢，是跟上面所说的动态加载js的优势是一样的，也是独立js的加载、解析，解析完成的时候就立即添加到UI Queue队列中去等待执行，阻塞后面的UI Update行为。
</p>
<p>
那么怎样将js的执行对UI Update的影响更小呢？使用HTML5的Worker机制吧，将复杂的js执行交给Worker去执行，Worker是一个独立的js执行环境，这个环境里没有window、DOM的概念，只是用来处理复杂的运算，再将处理后的结果通过postMessage方法发送会浏览器，Worker和页面之间通过postMessage方法来实现跟浏览器的数据交换。这样，将复杂运算交给Worker之后，在页面中所执行的js代码，将会是大大的减小，减小到只需要处理一个onmessage事件，将页面的js执行时间最小化。
</p>
<p>
杯具的还是defer、async、Worker还不能够完全的被目前市面上流行的浏览器所兼容，期待浏览器统一的那一天。
</p>
<p>
&#8212;- EOF &#8212;-</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1322/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>说说将Javascript和CSS合并为一个文件</title>
		<link>http://www.ilovejs.net/archives/1309</link>
		<comments>http://www.ilovejs.net/archives/1309#comments</comments>
		<pubDate>Thu, 04 Nov 2010 04:04:10 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[性能优化]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[合并]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1309</guid>
		<description><![CDATA[今天逛网的时候，看到一种技巧是将js代码和css代码混合在一起，利用CSS parser和Js parser的解析原理，来区分两种不同的代码。这个技巧估计老早就有人知道并讨论的乱套了，我又凹凸了一回。（合并javascript和css作为一个文件，Combine CSS with JS and make it into a single download!，Squeeze CSS and JS into one file） 起初看到这个标题觉得很惊奇，细看了上面罗列的文章之后，发现也只是利用了解析器的原理（解析器本来就是这么设计的，或许不是bug吧），对&#60;!- &#8230; <a href="http://www.ilovejs.net/archives/1309" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
今天逛网的时候，看到一种技巧是将js代码和css代码混合在一起，利用CSS parser和Js parser的解析原理，来区分两种不同的代码。这个技巧估计老早就有人知道并讨论的乱套了，我又凹凸了一回。（<a  href="http://hi.baidu.com/xzkcz/blog/item/61fb8313858a1cd8f7039eaa.html">合并javascript和css作为一个文件</a>，<a  href="http://blogs.msdn.com/b/shivap/archive/2007/05/01/combine-css-with-js-and-make-it-into-a-single-download.aspx?PageIndex=1#comments">Combine CSS with JS and make it into a single download!</a>，<a  href="http://ajaxian.com/archives/squeeze-css-and-js-into-one-file">Squeeze CSS and JS into one file</a>）
</p>
<p>
起初看到这个标题觉得很惊奇，细看了上面罗列的文章之后，发现也只是利用了解析器的原理（解析器本来就是这么设计的，或许不是bug吧），对&lt;!- &#8211; 的处理的不同，来实现将js和css代码混合在一起的方法。从PLT(page load time)来讲，确实将两个HTTP请求减少到一个了，从某种程度上可以减少PLT，但是它所带来的负面的影响和风险也还是比较大的，比如：
</p>
<ol>
<li>增加了代码的复杂度，难以阅读。</li>
<li>增加了代码量。特别是需要在处理CSS代码的时候，每一行都需要添加&lt;!- -，这个无形中增加了文件的代码量。</li>
<li>无法进行代码压缩。</li>
<li>在IE下会出现出错的风险。经过测试发现：如果在body中存在&lt;!- &#8211; - -&gt;，或者在body和head标签之间存在这个HTML注释，在IE下就会出错。<a  href="/lab/js-css-ie.html">试试看</a></li>
</ol>
<p>
所以并不太推荐使用，也不太看好。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1309/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>内容本地存储化的设想</title>
		<link>http://www.ilovejs.net/archives/1285</link>
		<comments>http://www.ilovejs.net/archives/1285#comments</comments>
		<pubDate>Sun, 17 Oct 2010 07:57:13 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[代码设计]]></category>
		<category><![CDATA[性能优化]]></category>
		<category><![CDATA[本地存储]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1285</guid>
		<description><![CDATA[今天在看博客的时候，萌生了这样的一种想法，目前博客更新不是很快，那么相对来说，很多内容都是在一定时间内保持不变的，那么就相当于是一个静态的内容，既然是相对静态的内容，那么每次访问的时候还从服务器的MySql数据库读取相同的内容，这就造成了一定的服务器端资源的浪费，如果可以将这些相对静态的内容使用客户端存储技术在本地存储起来，在单个用户再次访问的时候，直接从本地存储中读取静态的内容，而无需从服务端读取内容，那么页面的初始化将会是更加的快速，另一方面也可以最大化的节省流量。 对于使用wordpress博客系统架设的博客，页面中的模块是比较清晰的：导航、文章列表、目录、标签云、友情链接、搜索框等等，如果将这些模块都储存在本地，在内容没有更新的情况下，就相当于是一个“离线版”的页面了，无需借助于服务器，也能够浏览页面了。 从上面的想法出发，想在本人的博客进行测试，可是遇到了这样的问题：对于像友情链接、导航、搜索框等这些会“静态化”很久的内容，虽然进行了客户端存储，但是如果纯粹是从客户端进行判断是否内容有更新的话，还是得从服务端读取相应的内容进行判断，这样还是的查询数据库、加载内容，这样就没有意义了；如何利用服务器的“推技术”，使得内容有更新的时候，服务器才加载更新的模块，没有更新的模块仍然从本地存储中读取，或者更极端的是，只加载更新的具体的内容，而在同一个模块内没有更新的内容依然从本地读取。 对于本人的博客来说，想到了这样的一种方案： 将页面中的内容模块化，区分哪些是及时更新的（随机文章）、哪些是需要根据更新内容驱动来更新的（标签云、目录、导航、文章列表、友情链接）。 接着将那些不是即时更新的内容模块存进数据库的一个表里（或者也可以是存进一个txt、xml文件里），使用唯一的key做标记，这样在一个用户第一次读取页面，初始化每一个模块的时候，就会从这些储存了每个模块的txt或者xml文件里读取内容，而不需要从数据库去查询。但是这样就需要在后台更新内容的时候，就读取更新后的内容并更新这些文件的内容。 在每个用户第一次读取页面的时候，onload之后就将每一个txt的文件进行本地储存。并且通过服务端的检测文件是否有更新来输出js代码来判断是从服务端读取txt或者xml文件读取内容，还是从本地读取模块内容。 上面的方式涉及到很多地方的修改，所以实现起来比较繁琐，这个就需要在架构系统的时候就有这样的一种本地存储化的机制。并且，上面的方式还有一个致命的问题：当我是通过ftp软件直接修改相应的模块的静态内容，这样就得不到及时更新的文件，除非是直接修改存储相应模块的txt文件或者xml文件。也或者写一个自动化的脚本，运行一下程序，查询系统，更新全部模块的信息到txt文件里。 想法归想法，还需一步一步的来实现，也希望大家有更好的方式提出来一起讨论、分享……分享乃万善之本也。]]></description>
			<content:encoded><![CDATA[<p>
今天在看博客的时候，萌生了这样的一种想法，目前博客更新不是很快，那么相对来说，很多内容都是在一定时间内保持不变的，那么就相当于是一个静态的内容，既然是相对静态的内容，那么每次访问的时候还从服务器的MySql数据库读取相同的内容，这就造成了一定的服务器端资源的浪费，如果可以将这些相对静态的内容使用客户端存储技术在本地存储起来，在单个用户再次访问的时候，直接从本地存储中读取静态的内容，而无需从服务端读取内容，那么页面的初始化将会是更加的快速，另一方面也可以最大化的节省流量。
</p>
<p><span id="more-1285"></span></p>
<p>
对于使用wordpress博客系统架设的博客，页面中的模块是比较清晰的：导航、文章列表、目录、标签云、友情链接、搜索框等等，如果将这些模块都储存在本地，在内容没有更新的情况下，就相当于是一个“离线版”的页面了，无需借助于服务器，也能够浏览页面了。
</p>
<p>
从上面的想法出发，想在本人的博客进行测试，可是遇到了这样的问题：对于像友情链接、导航、搜索框等这些会“静态化”很久的内容，虽然进行了客户端存储，但是如果纯粹是从客户端进行判断是否内容有更新的话，还是得从服务端读取相应的内容进行判断，这样还是的查询数据库、加载内容，这样就没有意义了；如何利用服务器的“推技术”，使得内容有更新的时候，服务器才加载更新的模块，没有更新的模块仍然从本地存储中读取，或者更极端的是，只加载更新的具体的内容，而在同一个模块内没有更新的内容依然从本地读取。
</p>
<p>
对于本人的博客来说，想到了这样的一种方案：
</p>
<ol>
<li>将页面中的内容模块化，区分哪些是及时更新的（随机文章）、哪些是需要根据更新内容驱动来更新的（标签云、目录、导航、文章列表、友情链接）。</li>
<li>接着将那些不是即时更新的内容模块存进数据库的一个表里（或者也可以是存进一个txt、xml文件里），使用唯一的key做标记，这样在一个用户第一次读取页面，初始化每一个模块的时候，就会从这些储存了每个模块的txt或者xml文件里读取内容，而不需要从数据库去查询。但是这样就需要在后台更新内容的时候，就读取更新后的内容并更新这些文件的内容。</li>
<li>在每个用户第一次读取页面的时候，onload之后就将每一个txt的文件进行本地储存。并且通过服务端的检测文件是否有更新来输出js代码来判断是从服务端读取txt或者xml文件读取内容，还是从本地读取模块内容。</li>
</ol>
<p>
上面的方式涉及到很多地方的修改，所以实现起来比较繁琐，这个就需要在架构系统的时候就有这样的一种本地存储化的机制。并且，上面的方式还有一个致命的问题：当我是通过ftp软件直接修改相应的模块的静态内容，这样就得不到及时更新的文件，除非是直接修改存储相应模块的txt文件或者xml文件。也或者写一个自动化的脚本，运行一下程序，查询系统，更新全部模块的信息到txt文件里。
</p>
<p>
想法归想法，还需一步一步的来实现，也希望大家有更好的方式提出来一起讨论、分享……分享乃万善之本也。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1285/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>性能优化总结</title>
		<link>http://www.ilovejs.net/archives/1274</link>
		<comments>http://www.ilovejs.net/archives/1274#comments</comments>
		<pubDate>Fri, 15 Oct 2010 06:38:19 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[性能优化]]></category>
		<category><![CDATA[优化步骤]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1274</guid>
		<description><![CDATA[关于性能优化方面的关注点，每天都能够朗朗上口，但是当具体拿出一个页面给你去优化的时候，有可能你会不知道如何去展开优化工作和步骤（前几天有个朋友让我去优化一个网站首页，开始我就处于这种状态，很杯具~），也可能是想到一点就优化一点，乱套了。从而缺乏一个整体思路性的优化步骤。当我想到了这一点，就开始着手去总结这个一个优化流程的东西。 当然了，做优化的脱离不了浏览器，也脱离不了工具，为此，你手上得准备好一下几个工具：Google的Page Speed，Yahoo的YSlow，HTTPWatch，dynaTrace AJAX，Fiddler，Firebug。现在主流浏览器都集成了开发人员工具，提供了NET面板可以查看HTTP请求瀑布图，这是个好事情。 一切前提条件都就绪了，那么接下来罗列一下我认为的优化的流程，也是将来会指导我是思维的一个流程步骤吧： 一、查看HTTP瀑布图，一个是查看页面的加载时间，二是查看关键点：造成HTTP请求不能够并行加载的那些资源加载断层图（非IE：Firebug，IE：HTTPWatch；通用的是Fiddler；IE9自带了HTTP加载瀑布图）。 查看JavaScript的加载效果：js文件的加载、行内脚本是否阻塞其他资源的加载和页面渲染 查看CSS文件的加载：是否跟在行内脚本的后面，阻塞了后面资源的加载 第三方广告内容的加载是否影响了主页面资源的加载。这个可以通过是否存在过多的第三方域名造成的阻塞加载的请求 是否进行了多域名分发加载资源。 页面在第二次加载的时候是否是从缓存中读取静态资源 查看资源加载是否有404s错误 查看页面是否造成了重定向（包含301、302请求状态码） 资源的加载顺序是否正常：是否按照重要的优先级正确的顺序加载（CSS、js文件的加载方式是否正确）。 二、查看静态资源的请求头和响应头。特别是js、css、html文档，以及图片是否设置了Expires、max-age、Last-Modified、Etag请求头。 是否启用了gzip压缩 查看请求头中是否存在了多大的cookie 是否对静态资源启用了缓存机制（Expires、cache-control、max-age、Last-Modified、Etag等请求头） 是否有Transfer-Encoding:chunked响应头。这个响应头的作用是使得HTML文档可以边加载内容边解析页面 三、查看页面图片。 &#8230; <a href="http://www.ilovejs.net/archives/1274" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
关于性能优化方面的关注点，每天都能够朗朗上口，但是当具体拿出一个页面给你去优化的时候，有可能你会不知道如何去展开优化工作和步骤（前几天有个朋友让我去优化一个网站首页，开始我就处于这种状态，很杯具~），也可能是想到一点就优化一点，乱套了。从而缺乏一个整体思路性的优化步骤。当我想到了这一点，就开始着手去总结这个一个优化流程的东西。
</p>
<p>
当然了，做优化的脱离不了浏览器，也脱离不了工具，为此，你手上得准备好一下几个工具：Google的<a  href="http://code.google.com/intl/zh-CN/speed/page-speed/">Page Speed</a>，Yahoo的<a  href="http://developer.yahoo.com/yslow/">YSlow</a>，<a  href="http://www.httpwatch.com/">HTTPWatch</a>，<a  href="http://ajax.dynatrace.com/pages/">dynaTrace AJAX</a>，<a  href="http://www.fiddler2.com/fiddler2/">Fiddler</a>，<a  href="https://addons.mozilla.org/en-US/firefox/addon/1843/">Firebug</a>。现在主流浏览器都集成了开发人员工具，提供了NET面板可以查看HTTP请求瀑布图，这是个好事情。
</p>
<p>
一切前提条件都就绪了，那么接下来罗列一下我认为的优化的流程，也是将来会指导我是思维的一个流程步骤吧：
</p>
<p><span id="more-1274"></span></p>
<p>
一、<strong>查看HTTP瀑布图，一个是查看页面的加载时间，二是查看关键点：造成HTTP请求不能够并行加载的那些资源加载断层图（非IE：Firebug，IE：HTTPWatch；通用的是Fiddler；IE9自带了HTTP加载瀑布图）。</strong>
</p>
<ol>
<li>查看JavaScript的加载效果：js文件的加载、行内脚本是否阻塞其他资源的加载和页面渲染</li>
<li>查看CSS文件的加载：是否跟在行内脚本的后面，阻塞了后面资源的加载</li>
<li>第三方广告内容的加载是否影响了主页面资源的加载。这个可以通过是否存在过多的第三方域名造成的阻塞加载的请求</li>
<li>是否进行了多域名分发加载资源。</li>
<li>页面在第二次加载的时候是否是从缓存中读取静态资源</li>
<li>查看资源加载是否有404s错误</li>
<li>查看页面是否造成了重定向（包含301、302请求状态码）</li>
<li>资源的加载顺序是否正常：是否按照重要的优先级正确的顺序加载（CSS、js文件的加载方式是否正确）。</li>
</ol>
<p>
二、<strong>查看静态资源的请求头和响应头。特别是js、css、html文档，以及图片是否设置了Expires、max-age、Last-Modified、Etag请求头。</strong>
</p>
<ol>
<li>是否启用了gzip压缩</li>
<li>查看请求头中是否存在了多大的cookie</li>
<li>是否对静态资源启用了缓存机制（Expires、cache-control、max-age、Last-Modified、Etag等请求头）</li>
<li>是否有Transfer-Encoding:chunked响应头。这个响应头的作用是使得HTML文档可以边加载内容边解析页面</li>
</ol>
<p>
三、<strong>查看页面图片。</strong>
</p>
<ol>
<li>查看页面中图片是否被强制进行了缩放，并且查看页面的img标签是否设置了跟图片尺寸一样的height、width属性。</li>
<li>CSS背景修饰图片是否sprites了</li>
<li>图片是否经过优化（清除元数据），通过Page Speed就可以检测出来</li>
</ol>
<p>
四、<strong>查看DOM文档树以及页面源代码</strong>
</p>
<ol>
<li>页面是否存在过多的iframe</li>
<li>Minify CSS、HTML、JavaScript，是否对CSS、Javascript进行了压缩，包括行内和外联的文件的代码，以及是否对HTML也进行了压缩</li>
<li>是否使用了HTML5的doctype声明方式</li>
<li>是否显示声明了charset</li>
<li>查看页面中css、js文件以及行内样式、行内脚本的位置是否正确。</li>
<li>查看body标签内是否存在过多的style行内样式。因为body标签内的行业样式一方面会造成整体样式的重绘、造成页面样式的闪白，另一方面也可能会阻塞页面的渲染和资源的加载。</li>
<li>查看body标签中（除了底部的之外）是否存在过多的script行内脚本阻塞页面资源的渲染和加载。行内脚本所造成的阻塞是全局性的，在解析js代码期间，页面也一切行为都会受到阻塞。</li>
<li>通过dynaTrace AJAX工具查看页面初始化的情况，查看页面渲染时间、脚本解析时间等等方面的信息，查看脚本的执行时间是否过长。</li>
</ol>
<p>
五、<strong>在表面可以直接看到的之后，再根据页面的特点和功能，在不改变页面功能的情况下，改善代码，优化页面的初始化速度。</strong>
</p>
<ol>
<li>服务端代码是否进行了优化，比如刷新输出……</li>
<li>比如一些需要按用户需求来驱动的功能，这样的一些资源有两种方案可以解决：一是用户操作之后，就开始初始化组件，并给予一个良好的提示信息；而是使用页面的onload事件之后加载额外的内容。综合各方面的原因，推荐使用第一种方式，因为它是按需加载的，只要需要它的时候才加载资源，不需要的话就不加载，这样可以尽可能的减少页面的流量。</li>
<li>一些内容在页面初始化过程中是隐藏的话，那么就可以在页面初始化的时候，这些隐藏的内容就不随页面的初始化而加载进来了，特别是图片资源的记载。</li>
<li>尽量拆分页面中js文件，哪些是需要页面在初始化的时候就必须要执行的代码，哪些不是页面初始化所必须的；还有一种情况是那些js代码是页面初始化的时候就需要实例化或者执行的，哪些又是不需要的，对于不需要页面初始化就执行的代码，建议是按需进行实例化或者执行，等到需要它的时候才进行实例化。</li>
</ol>
<p>
上面所罗列的优化步骤，也只是一个指导，还有很多可优化的方面还没有涉及到，有待逐步完善，而且随着性能优化逐渐深入，可优化的空间还会越来越多的，关注点也会越来越细。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1274/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Fetch resources on-demand</title>
		<link>http://www.ilovejs.net/archives/1258</link>
		<comments>http://www.ilovejs.net/archives/1258#comments</comments>
		<pubDate>Mon, 11 Oct 2010 17:01:17 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Ajax]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[性能优化]]></category>
		<category><![CDATA[按需加载]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1258</guid>
		<description><![CDATA[Fetch resources on-demand，中文意思大概就是按需加载资源，而这里的资源不只是CSS、JS文件，Image、swf、Content等都可以利用这种方式。特别是当前Yahoo的首页：http://www.yahoo.com，几乎页面的每一个模块都体现了按需加载的技巧：左边的导航（用户可以定制、点击异步请求更多资源）、中间的新闻、图片tab、右栏的第三方资源等等。 按需加载表面理解起来很简单，但是怎么个按需法呢？我所理解的按需，包括两个方面：一个是按用户的需要；另一个是网站本身的需要。按需加载主要解决的问题就是加快页面的初始化以及在页面初始化的时候最大化减少HTTP请求，因为有些模块比如：图片导航tab、多级菜单、内容导航等等，这些在初始化页面的时候有很多内容都是处于隐藏状态，用户是看不到的，那么这些内容对不同的用户来说有不同的需求，那么这些就可以从页面的初始化中剥离出来，按用户的需求通过异步通信来加载内容和资源。对于网站本身的需要来加载后续资源，比如Google首页对于结果页的一些js、image等资源的pre-fetch的方式，通过分析用户可能会产生的行为，为后续的页面提前加载内容，加快后续页面的初始化速度，从缓存中读取页面所需要的资源。 接下来分析一下淘宝首页（http://www.taobao.com）的一些按需加载的技巧。首先对于中间栏的这个部分的实现： 看这个模块的源码之后发现，除了初始化第一个tab内容之后，后面隐藏的几个tab的资源是没有加载的，它是将这些资源的HTML设置到一个隐藏的textarea控件的值里面，在点击了左右的导航按钮之后，就读出这个textarea的内容并解析到tab中，当然这也同时是加载图片等资源。我想，这样做的一个好处就是上面说的按需加载，加快页面的初始化速度；还有另外一个作用是减少页面初始化的DOM节点数。将这个添加更多DOM节点推迟到按照用户的需要去点击导航按钮。这个在加快页面的初始化方面也是很不错的技巧。 再来分析一下Yahoo首页的其中一个模块的实现方式，也是比较类似的： 如上图，在下部的导航中，初始化的时候会默认加载一个tab看到的导航的图片和问题，而其他隐藏的每一个导航tab，在页面初始化的时候HTML的结构均使用四个span标签代替，之后在点击左右导航按钮的时候，进行异步请求资源，并替换掉每一个相应的span标签。它在初始化页面的时候使用span标签，只是为了保持一个高度上的“空架子”，在之后的按需请求中往这个架子中替换内容，这样其中的一个原因可能是为了不至于在替换标签的时候在高度上的过度出现闪烁。 按需加载的思维在很多网站中都有体现，利用Ajax技术，异步请求内容，将隐藏的内容、资源的加载跟页面的初始化剥离开来，加快页面的初始化。]]></description>
			<content:encoded><![CDATA[<p>
Fetch resources on-demand，中文意思大概就是按需加载资源，而这里的资源不只是CSS、JS文件，Image、swf、Content等都可以利用这种方式。特别是当前Yahoo的首页：<a  href="http://www.yahoo.com">http://www.yahoo.com</a>，几乎页面的每一个模块都体现了按需加载的技巧：左边的导航（用户可以定制、点击异步请求更多资源）、中间的新闻、图片tab、右栏的第三方资源等等。
</p>
<p>
按需加载表面理解起来很简单，但是怎么个按需法呢？我所理解的按需，包括两个方面：一个是按用户的需要；另一个是网站本身的需要。按需加载主要解决的问题就是加快页面的初始化以及在页面初始化的时候最大化减少HTTP请求，因为有些模块比如：图片导航tab、多级菜单、内容导航等等，这些在初始化页面的时候有很多内容都是处于隐藏状态，用户是看不到的，那么这些内容对不同的用户来说有不同的需求，那么这些就可以从页面的初始化中剥离出来，按用户的需求通过异步通信来加载内容和资源。对于网站本身的需要来加载后续资源，比如Google首页对于结果页的一些js、image等资源的pre-fetch的方式，通过分析用户可能会产生的行为，为后续的页面提前加载内容，加快后续页面的初始化速度，从缓存中读取页面所需要的资源。
</p>
<p><span id="more-1258"></span></p>
<p>
接下来分析一下淘宝首页（<a  href="http://www.taobao.com">http://www.taobao.com</a>）的一些按需加载的技巧。首先对于中间栏的这个部分的实现：
</p>
<p>
<img src="http://www.ilovejs.net/wp-content/uploads/2010/10/taobao.jpg" alt="" title="taobao" width="478" height="143" class="alignnone size-full wp-image-1259" />
</p>
<p>
看这个模块的源码之后发现，除了初始化第一个tab内容之后，后面隐藏的几个tab的资源是没有加载的，它是将这些资源的HTML设置到一个隐藏的textarea控件的值里面，在点击了左右的导航按钮之后，就读出这个textarea的内容并解析到tab中，当然这也同时是加载图片等资源。我想，这样做的一个好处就是上面说的按需加载，加快页面的初始化速度；还有另外一个作用是减少页面初始化的DOM节点数。将这个添加更多DOM节点推迟到按照用户的需要去点击导航按钮。这个在加快页面的初始化方面也是很不错的技巧。
</p>
<p>
再来分析一下Yahoo首页的其中一个模块的实现方式，也是比较类似的：
</p>
<p>
<img src="http://www.ilovejs.net/wp-content/uploads/2010/10/yahoo1.jpg" alt="" title="yahoo" width="403" height="440" class="alignnone size-full wp-image-1261" />
</p>
<p>
如上图，在下部的导航中，初始化的时候会默认加载一个tab看到的导航的图片和问题，而其他隐藏的每一个导航tab，在页面初始化的时候HTML的结构均使用四个span标签代替，之后在点击左右导航按钮的时候，进行异步请求资源，并替换掉每一个相应的span标签。它在初始化页面的时候使用span标签，只是为了保持一个高度上的“空架子”，在之后的按需请求中往这个架子中替换内容，这样其中的一个原因可能是为了不至于在替换标签的时候在高度上的过度出现闪烁。
</p>
<p>
按需加载的思维在很多网站中都有体现，利用Ajax技术，异步请求内容，将隐藏的内容、资源的加载跟页面的初始化剥离开来，加快页面的初始化。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1258/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>所谓的javascript高级技巧</title>
		<link>http://www.ilovejs.net/archives/1232</link>
		<comments>http://www.ilovejs.net/archives/1232#comments</comments>
		<pubDate>Fri, 01 Oct 2010 16:00:29 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[性能优化]]></category>
		<category><![CDATA[高级技巧]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1232</guid>
		<description><![CDATA[Js学的也差不多了，该是来总结一下Js中一些比较高级的智慧结晶了。基于Js的动态性、对象都是易变的、函数是第一对象等等其他语言所不包含的特性，可以在使用Js的时候创造出更高效、组织性更好的代码。下面提到的一些概念，是不是很熟悉： 分支、惰性实例化、惰性载入函数、单例的两种模式、享元类、函数绑定（纠正函数一个执行上下文）、函数curry化、高级定时器、保护上下文的构造函数、函数节流、自定义事件…… js中的继承、原型、构造函数这些都是老生常谈的了。但是对于构造函数式继承和原型式继承的优缺点，还是有必要了解一下的。原型式继承的主要优点就是共享方法和属性，使得从原型对象中继承出来的子对象都可以在内存中共享全部的方法和属性，这如果是在大型的继承链中将会大大的改善性能和减少内存的使用量。 接下来看看上面所罗列的每一个所谓的“高级”技巧的具体细节咧： 惰性实例化 惰性实例化所要解决的问题是这样的：避免了在页面中js初始化执行的时候就实例化了类，如果在页面中没有使用到这个实例化的对象，那么这就造成了一定的内存的浪费和性能的消耗，那么如果将一些类的实例化推迟到需要使用它的时候才开始去实例化，那么这就避免了刚才说的问题，做到了“按需供应”，简单代码示例如下： [javascript] var myNamespace = function(){ var Configure = function(){ var privateName = &#34;someone&#8217;s name&#34;; &#8230; <a href="http://www.ilovejs.net/archives/1232" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
Js学的也差不多了，该是来总结一下Js中一些比较高级的智慧结晶了。基于Js的动态性、对象都是易变的、函数是第一对象等等其他语言所不包含的特性，可以在使用Js的时候创造出更高效、组织性更好的代码。下面提到的一些概念，是不是很熟悉：
</p>
<p>
分支、惰性实例化、惰性载入函数、单例的两种模式、享元类、函数绑定（纠正函数一个执行上下文）、函数curry化、高级定时器、保护上下文的构造函数、函数节流、自定义事件……
</p>
<p>
js中的继承、原型、构造函数这些都是老生常谈的了。但是对于构造函数式继承和原型式继承的优缺点，还是有必要了解一下的。原型式继承的主要优点就是共享方法和属性，使得从原型对象中继承出来的子对象都可以在内存中共享全部的方法和属性，这如果是在大型的继承链中将会大大的改善性能和减少内存的使用量。
</p>
<p><span id="more-1232"></span></p>
<p>
接下来看看上面所罗列的每一个所谓的“高级”技巧的具体细节咧：
</p>
<ol>
<li><b>惰性实例化</b><br />
惰性实例化所要解决的问题是这样的：避免了在页面中js初始化执行的时候就实例化了类，如果在页面中没有使用到这个实例化的对象，那么这就造成了一定的内存的浪费和性能的消耗，那么如果将一些类的实例化推迟到需要使用它的时候才开始去实例化，那么这就避免了刚才说的问题，做到了“按需供应”，简单代码示例如下：<br />
[javascript]<br />
var myNamespace = function(){<br />
   var Configure = function(){<br />
     var privateName = &quot;someone&#8217;s name&quot;;<br />
	 var privateReturnName = function(){<br />
	   return privateName;<br />
	 }<br />
	 var privateSetName = function(name){<br />
	   privateName = name;<br />
	 }<br />
	 //返回单例对象<br />
	 return {<br />
	   setName:function(name){<br />
	     privateSetName(name);<br />
	   },<br />
	   getName:function(){<br />
	     return privateReturnName();<br />
	   }<br />
	 }<br />
   }<br />
   //储存configure的实例<br />
   var instance;</p>
<p>   return {<br />
     getInstance:function(){<br />
	   if(!instance){<br />
	     instance = Configure();<br />
	   }<br />
	   return instance;<br />
	 }<br />
   }<br />
}();<br />
//使用方法上就需要getInstance这个函数作为中间量了：<br />
myNamespace.getInstance().getName();<br />
[/javascript]<br />
上面的就是简单的惰性实例化的示例，但是有一点缺点就是需要使用中间量来调用内部的Configure函数所返回的对象的方法（当然也可以使用变量来储存myNamespace.getInstance()返回的实例对象）。将上面的代码稍微修改一下，就可以只用比较得体的方法来使用内部的方法和属性：<br />
[javascript]<br />
//惰性实例化的变体<br />
var myNamespace2 = function(){<br />
   var Configure = function(){<br />
     var privateName = &quot;someone&#8217;s name&quot;;<br />
	 var privateReturnName = function(){<br />
	   return privateName;<br />
	 }<br />
	 var privateSetName = function(name){<br />
	   privateName = name;<br />
	 }<br />
	 //返回单例对象<br />
	 return {<br />
	   setName:function(name){<br />
	     privateSetName(name);<br />
	   },<br />
	   getName:function(){<br />
	     return privateReturnName();<br />
	   }<br />
	 }<br />
   }<br />
   //储存configure的实例<br />
   var instance;</p>
<p>   return {<br />
     init:function(){<br />
	   //如果不存在实例，就创建单例实例<br />
	   if(!instance){<br />
	     instance = Configure();<br />
	   }<br />
	   //将Configure创建的单例<br />
	   for(var key in instance){<br />
	     if(instance.hasOwnProperty(key)){<br />
		   this[key]=instance[key];<br />
		 }<br />
	   }<br />
	   this.init = null;<br />
	   return this;<br />
	 }<br />
   }<br />
}();<br />
//使用方式：<br />
myNamespace2.init();<br />
myNamespace2.getName();<br />
[/javascript]<br />
上面修改了自执行函数返回的对象的代码，在获取Configure函数返回的对象的时候，将该对象的方法赋给myNamespace2，这样，调用方式就发生了一点改变了。
</li>
<li><b>分支</b><br />
分支技术解决的一个问题是处理浏览器之间兼容性的重复判断的问题。普通解决浏览器之间的兼容性的方式是使用if逻辑来进行特性检测或者能力检测，来实现根据浏览器不同的实现来实现功能上的兼容，但问题是，没执行一次代码，可能都需要进行一次浏览器兼容性方面的检测，这个是没有必要的，能否在代码初始化执行的时候就检测浏览器的兼容性，在之后的代码执行过程中，就无需再进行检测了呢？答案是有的，分支技术就可以解决这个问题（同样，惰性载入函数也可以实现Lazy Definied，这个在后面将会讲到），下面以声明一个XMLHttpRequest实例对象为例子：<br />
[javascript]<br />
//分支<br />
var XHR= function(){<br />
  var standard = {<br />
    createXHR : function(){<br />
	  return new XMLHttpRequest();<br />
	}<br />
  }<br />
  var newActionXObject = {<br />
    createXHR : function(){<br />
	  return new ActionXObject(&quot;Msxml2.XMLHTTP&quot;);<br />
	}<br />
  }<br />
  var oldActionXObject = {<br />
    createXHR : function(){<br />
	  return new ActionXObject(&quot;Microsoft.XMLHTTP&quot;);<br />
	}<br />
  }<br />
  if(standard.createXHR()){<br />
    return standard;<br />
  }else{<br />
    try{<br />
	  newActionXObject.createXHR();<br />
	  return newActionXObject;<br />
	}catch(o){<br />
	  oldActionXObject.createXHR();<br />
	  return oldActionXObject;<br />
	}<br />
  }<br />
}();<br />
[/javascript]</p>
<p>
从上面的例子可以看出，分支的原理就是：声明几个不同名称的对象，但是给这些对象都声明一个名称相同的方法（这个就是关键），并给这些来自于不同的对象但是拥有相同的方法进行浏览器之间各自的实现，接着就开始进行一次浏览器检测，并经过浏览器检测的结果来决定返回哪一个对象，这样不论返回的是哪一个对象，最后名称相同的方法都作为了对外一致的接口。
</p>
<p>这个是在Javascript运行期期间进行动态检测，并将检测的结果返回赋值给其他的对象，并提供相同的接口，这样储存的对象就可以使用名称相同的接口了。其实，惰性载入函数跟分支在原理是非常相近的，只是在代码实现方面有差异而已。
</li>
<li><b>惰性载入函数</b><br />
惰性载入函数就是英文中传说的“Lazy Defined”，它的主要解决的问题也是为了处理兼容性。原理跟分支类似，下面是简单的代码示例：<br />
[javascript]<br />
var addEvent = function(el,type,handle){<br />
  addEvent = el.addEventListener ? function(el,type,handle){<br />
    el.addEventListener(type,handle,false);<br />
  }:function(el,type,handle){<br />
    el.attachEvent(&quot;on&quot;+type,handle);<br />
  };<br />
  //在第一次执行addEvent函数时，修改了addEvent函数之后，必须执行一次。<br />
  addEvent(el,type,handle);<br />
}<br />
[/javascript]<br />
从代码上看，惰性载入函数也是在函数内部改变自身的一种方式，这样之后，当重复执行的时候，就不会再进行兼容性方面的检测了。
</li>
<li><b>单例的两种模式</b><br />
单例模式是家喻户晓的了，也是当前最流行的一种编写方式，注明的模块模式的编写方式也是从这个思想中衍生出来的。单例模式有两种方式：一种是所谓的“门户大开型”，另外一种就是使用闭包来创建私有属性和私有方法的方式。第一种方式跟构造函数的“门户大开型”是一个样的，声明的方法和属性对外都是开放的，可以通过实例来调用。但是使用闭包来实现的单例模式，可以在一个“封闭”的作用域内声明一些不为外部所调用的私有属性和私有方法，而且还有一个很主要的功能，就是私有属性可以作为一个“数据存储器”，在闭包内声明的方法都可以访问这些私有属性，但是外部不可访问。那么重复添加、修改、删除这些私有属性所储存的数据是安全的，不受外部其他程序的影响。
</li>
<li><b>享元类</b><br />
顾名思义，“享”、“元”。就是共享通用的方法和属性，将差异比较大的类中相同功能的方法集中到一个类中声明，这样需要这些方法的类就可以直接从享元类中进行扩展，这样使得这样通用的方法只需要声明一遍就行了。这个从代码的大小、质量来说还是有一定的效益的。
</li>
<li><b>函数绑定</b><br />
函数绑定就是为了纠正函数的执行上下文，特别是函数中带有this关键字的时候，这点尤其显得重要，稍微不小心，使得函数的执行上下文发生了跟预期的不同的改变，导致了代码执行上的错误（有时候也不会出现错误，这样调试起来，会很变态）。对于这个问题，bind函数是再熟悉不过的了，bind函数的功能就是提供一个可选的执行上下文传递给函数，并且在bind函数内部返回一个函数，来纠正在函数调用上出现的执行上下文发生的变化。最容易出现的错误就是回调函数和事件处理程序一起使用了，下面是摘自《Javascript高级程序设计第二版》的一个示例：<br />
[javascript]<br />
var handler = {<br />
  message:&quot;Event handler&quot;,<br />
  handlerClick:function(e){<br />
    alert(this.message);<br />
  }<br />
}<br />
var btn = document.getElementById(&quot;my-btn&quot;);<br />
//这句就造成了回调函数执行上下文的改变了<br />
EventUtil.addHandler(btn,&quot;click&quot;,handler.handlerClick);<br />
[/javascript]<br />
解决的办法之一，就是纠正一下handler.handlerClick执行的上下文环境，改为：<br />
[javascript]<br />
//这样运行的很好<br />
EventUtil.addHandler(btn,&quot;click&quot;,function(e){<br />
  handler.handlerClick(e);<br />
});<br />
[/javascript]<br />
上面就很好的纠正了回调函数的执行上下文了。而且，也可以使用传说中的bind函数来解决：<br />
[javascript]<br />
var bind = function(fn,context){<br />
  return function(){<br />
     return fn.apply(context || this,arguments);<br />
  }<br />
}<br />
EventUtil.addHandler(btn,&quot;click&quot;,bind(handler.handlerClick));// So Good！<br />
[/javascript]
</li>
<li><b>函数curry化</b><br />
函数curry化的主要功能就是提供了强大的动态函数创建的功能。通过调用另一个函数并为它传入要curry的函数和必要的参数。说白点就是利用已有的函数，再创建一个动态的函数，该动态的函数内部还是通过该已有的函数来发生作用，只是传入更多的参数来简化函数的参数方面的调用。具体示例：<br />
[javascript]<br />
//curry function<br />
function curry(fn){<br />
  var args = [].slice.call(arguments,1); //这个就相当于一个存储器了。<br />
  return function(){<br />
    return fn.apply(null,args.concat([].slice.call(arguments,0)));<br />
  }<br />
}<br />
//Usage:<br />
function add(num1,num2){<br />
  return num1+num2;<br />
}<br />
var newAdd = curry(add,5);<br />
alert(newAdd(6));<br />
[/javascript]<br />
在curry函数的内部，私有变量args就相当于一个存储器，来暂时的存储在curry函数调用的时候所传递的参数值，这样跟后面的动态创建的函数调用的时候的参数合并，并执行，就得到了一样的效果了。
</li>
<li><b>高级定时器</b><br />
提到定时器，无非就是利用setTimeout/setInterval了。但问题是定时器并不是相当于新开一个线程来执行js程序，也不会说是在指定的时间间隔内就会一定执行。指定的时间间隔表示何时将定时器的代码添加到浏览器的执行队列，而不是合适实际执行代码。对此，就有这样的一个问题了：如果代码执行时间超过了定时器指定的时间间隔，那么在指定的时间里代码还是加入的执行队列，但是并没有执行，这样就会造成了无意义的代码执行，这也是使用setInterval的弊端。为此，使用setTimeout才能更好的避免这个问题，在代码本身中执行完毕了，再通过setTimeout来重新设定定时器，把代码加入到执行队列。比如：<br />
[javascript]<br />
setTimeout(function(){<br />
  //many code here&#8230;<br />
  setTimeout(arguments.callee,100); //Key<br />
},100);<br />
[/javascript]<br />
当然了，定时器还有很多其他的技巧和实际作用，看需求而定，更详细的解释可以查看《Javascript高级程序设计第二版》（第467页）。
</li>
<li><b>保护上下文的构造函数</b><br />
这个主要是避免构造函数在没有使用new来实例化的时候，内部的this指向错误问题。通常没有使用new的话，this一般执行window去了，因此造成了执行错误，给代码带来了灾难。使用下面的方式就可以避免这个问题：<br />
[javascript]<br />
function myClass(name,size){<br />
  if(this instanceof myClass){  //Key,使用instanceof来检测当前实例是否是myClass的实例化对象<br />
    this.name = name;<br />
    this.size = size;<br />
 }else{<br />
    return new myClass(name,size);<br />
  }<br />
}<br />
[/javascript]</p>
<p>
但是上面通过instanceof的方式，给继承造成了一定的困扰，因为子类并不是myClass的实例对象，所以会出现属性和方法无法被继承的方式。在说解决办法之前，先来了解一下instanceof操作符的原理：它首先会检测对象当前的原型是否指向右边的构造函数，如果找不到，就会往上一级的原型去查找，直到找到为止，并返回true，否则就返回false。
</p>
<p>基于上面的instanceof的原理，在继承的时候，就可以给子类的prototype原型赋于一个父类的实例化对象就行了，这样就可以在子类继承的时候绕过instanceof的检测。
</li>
<li><b>函数节流</b>
<p>
函数节流函数节流解决的问题是一些代码（特别是事件）在无间断的执行，这严重的影响了浏览器的性能，再没有给它设定间断来执行的话，可能造成浏览器反应速度变慢或者直接就崩溃了。比如：resize事件、mousemove、mouseover、mouseout等等事件。
</p>
<p>
这个时候，就可以加入定时器的功能了，将事件进行“节流”，即是：在事件触发的时候，设定一个定时器来执行事件处理程序，这样可以很大的程度上缓解浏览器的负担，又缓冲的余地去更新页面。具体的实例可以查看支付宝中部“导购场景”的导航：<a  href="http://life.alipay.com/?src=life_alipay_index_big">http://life.alipay.com/?src=life_alipay_index_big</a>，以及当当网首页左边的导航栏：<a  href="http://www.dangdang.com/">http://www.dangdang.com/</a>等等，这些都是为了解决mouseover和mouseout移动过快的时候加大浏览器处理的负担，特别是在涉及到有Ajax调用，而且Ajax调用是么有缓存的情况下，给服务器也造成了很大的负担。为此，函数节流就派上用场了。比如简单的示例如下（出自本人写的：<a  href="http://www.ilovejs.net/lab/tween/tweener_tab_modify.html">http://www.ilovejs.net/lab/tween/tweener_tab_modify.html</a>）：<br />
[javascript]<br />
oTrigger.onmouseover=function(e){<br />
  //如果上一个定时器还没有执行，则先清除掉定时器<br />
  oContainer.autoTimeoutId &amp;&amp; clearTimeout(oContainer.autoTimeoutId);<br />
  e = e || window.event;<br />
  var target = e.target || e.srcElement;<br />
  if((/li$/i).test(target.nodeName)){<br />
    oContainer.timeoutId = setTimeout(function(){<br />
      addTweenForContainer(oContainer,oTrigger,target);<br />
    },300);<br />
   }<br />
}<br />
[/javascript]
</p>
</li>
<li><b>自定义事件</b>
<p>
首先要说的是，这里并不是说自定义事件可以真的自定义跟mouseout、click等一样性质的“事件”。这里的自定义事件在执行的时候还是需要依赖已有的键盘、鼠标、HTML等事件来执行，或者又其他函数“触发”执行，这里的“触发”是指直接调用自定义事件中声明的某个接口方法，来轮询的执行全部相关的添加到自定义事件中的函数。
</p>
<p>
自定义事件内部有一个“事件”存储器，根据添加的事件的类型的不同，来储存各类的事件执行函数，这样再出发这类事件的时候，就轮询执行添加到该类型下的函数。“自定义事件背后的概念是创建一个管理事件的对象，让其他对象监听那些事件”来自《Javascript高级程序设计第二版》的解释。基于自定义事件的原理，可以想象自定义事件很多时候是用于“订阅&#8212;发布&#8212;接收”性质的功能。
</p>
</li>
</ol>
<p>
文章写的有点多了，但是上面介绍的Javascript高级技巧还远不止这些，特别是在Ajax方面的一些模式和技巧都还没有介绍，何况是客户端和服务端结合的一些技巧（比如压缩、Minify、服务器“推技术”等等）。更多的有待以后了解了介绍一二。
</p>
<p>
在前端基本技术方面，Javascript、HTML、CSS等大家都是已经掌握的差不多了，但是利用这些已有的基本技术，能否创造出不一般的应用和模式呢？这个才是在掌握了基本的能力之后接下来需要掌握的，比如下面是本人在每天晚上睡觉之前所总结的几点：
</p>
<ol>
<li>学会重构代码的技术，有计划性的重构下自己之前所编写过的一些代码，加强自己掌控代码的能力。</li>
<li>Code review。这里说的review，并不是指个人，而是对团队来说的，一个人编写的代码的想象空间有限，如果在自己编写代码完成之后，邀请其他团队内的伙伴来查看你的代码，及时发现问题以及提出更好的解决方案，这也不失为一种即时重构的方式，提高代码的质量。</li>
<li>编写具体的功能代码之前，首先设计代码、规划代码、组织代码的模式。</li>
<li>在代码的质量、性能、大小之间能作出合理的权衡。</li>
<li>编写阅读性良好、一目了然、扩展性、可维护性良好、重复利用的代码，也是一门艺术。</li>
<li>关注web前端的性能优化，包括Javascript、HTML、CSS、客户端、服务端、前端、后端等整体性的优化。</li>
<li>最后一点或许也是最重要的：善于总结。这点比上面的任何一点都来的重要，因为上面的每一点都是出自这点的积累。</li>
</ol>
<p>上面我总结的几点，也是后期自己要着重提高的能力，当然了，在实际的编码方面，还有很多的东西还需要去挖掘和了解。继续革命吧，将互联网革命进行到底……</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1232/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>网站再优化</title>
		<link>http://www.ilovejs.net/archives/1156</link>
		<comments>http://www.ilovejs.net/archives/1156#comments</comments>
		<pubDate>Tue, 10 Aug 2010 16:44:56 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[性能优化]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[浏览器]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1156</guid>
		<description><![CDATA[今天闲来无事，就用Firebug查看首页的HTTP瀑布图，测试页面加载时间，发现在外联的css和js上时间开销还是挺大的，虽然css和js都进行了gzip压缩，但是解析延迟在某些时候还是比较厉害，不是css解析延迟就是js解析延迟，在读取缓存的时候，也有一定的读取的时间开销。 鉴于这种情况，那么干脆就将首页的css和js都嵌入到页面中吧，把css放到head、js放到body闭合标签之前，反正这两个文件在gzip压缩的条件下也总共才三四K而已，而子页面里还是使用外联css和js的方式。 经过这样倒弄，首页加载速度平均有100ms的提升，欣喜若狂。更好笑的是yslow、page speed测试都得了满分，哈哈…… 让首页嵌入css和js，而子页面外联的方式，主要是出于这样的一个目的：用户第一次浏览到首页的时候，页面可以尽快的呈现，而到了子页面，就加载css和js，这样的用户体验就有了一个类似于“稳步退化”的感觉，使得用户不会在起先的时候就有个不良感觉，而之后的访问，子页面就可以充分的利用缓存，因为子页面可能包含图片、flash等等，缓解HTTP的并发数。 还有，之前在浏览器下可能会有短暂的无样式与渲染样式之前切换的闪白，目前也得到了比较好的缓解。]]></description>
			<content:encoded><![CDATA[<p>
今天闲来无事，就用Firebug查看首页的HTTP瀑布图，测试页面加载时间，发现在外联的css和js上时间开销还是挺大的，虽然css和js都进行了gzip压缩，但是解析延迟在某些时候还是比较厉害，不是css解析延迟就是js解析延迟，在读取缓存的时候，也有一定的读取的时间开销。
</p>
<p>
鉴于这种情况，那么干脆就将首页的css和js都嵌入到页面中吧，把css放到head、js放到body闭合标签之前，反正这两个文件在gzip压缩的条件下也总共才三四K而已，而子页面里还是使用外联css和js的方式。
</p>
<p>
经过这样倒弄，首页加载速度平均有100ms的提升，欣喜若狂。更好笑的是yslow、page speed测试都得了满分，哈哈……
</p>
<p>
让首页嵌入css和js，而子页面外联的方式，主要是出于这样的一个目的：用户第一次浏览到首页的时候，页面可以尽快的呈现，而到了子页面，就加载css和js，这样的用户体验就有了一个类似于“稳步退化”的感觉，使得用户不会在起先的时候就有个不良感觉，而之后的访问，子页面就可以充分的利用缓存，因为子页面可能包含图片、flash等等，缓解HTTP的并发数。
</p>
<p>
还有，之前在浏览器下可能会有短暂的无样式与渲染样式之前切换的闪白，目前也得到了比较好的缓解。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1156/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>谈谈松散耦合、颗粒度</title>
		<link>http://www.ilovejs.net/archives/1129</link>
		<comments>http://www.ilovejs.net/archives/1129#comments</comments>
		<pubDate>Mon, 09 Aug 2010 18:07:06 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[性能优化]]></category>
		<category><![CDATA[query]]></category>
		<category><![CDATA[松散耦合]]></category>
		<category><![CDATA[颗粒度]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1129</guid>
		<description><![CDATA[“松散耦合”、“颗粒度”是相对于javascript库或者javascript框架来说的，它涉及的概念和包含的知识是很多的，而其中之一，就是说javascript库或者框架从整理来看是容易拆分，也容易自定义的组合，来实现特定需求的功能。之前有很多说法说YUI的编写方法才更接近于javascript的本质，虽然上手的门槛很高，但是对于一个真正的javascript程序员来说，反而更值得；而jQuery似乎另类了，改变了普通的编写javascript的编写方式，虽然说它封装的很好，“用最少的代码实现复杂的功能”，但是它的可读性就很差了，虽然门槛很低，毫无javascript基础的程序员在看了它的API文档之后都能够利用它写出很多丰富的效果。但是，作为程序员，这样下去行吗？ jQuery是毒药 &#8212;&#8212; 很多人都这么说。本人也举得，从一个程序员的成长来看，jQuery是弊大于利。我们更应该做的是学习它的原理和架构，而不是拿来用而已。 一个很经常会发生的问题：我只需要用到一个javascript库中的几个方法，却需要加载整个库的体积，而整个库封装的又十分复杂，拆分起来十分繁琐，怎么办？自己写呗…… 一个javascript库的本意虽然说是为了提高开发效率、解决浏览器的兼容性问题、统一开发规范以及解决安全隐患等等。但是在设计javascript库的时候，我们是不是应该多留多点空间给使用者去DIY它的具体的功能，让使用者多点接触到javascript的本质，以及非常容易的缩减库的体积呢？就从这几点出发，YUI3是比较符合“松散耦合”、“颗粒度”的原则的，虽然说jQuery可以通过fn方法来扩展，但都是基于它整个已经封装好的库来说的。但是YUI3也有它的缺点：学习成本高、整体体积庞大、可能一步小心在use方法里多加载几个文件，或者使用”*”，那么需要异步加载的js文件也是很多的、以及它内部组件之间的依赖关系也是比较复杂的。 为了说明我的想法，首先从我编写的query鸡查询函数（目前还没完善，先拿来做例子）开始说起，我的想法是：只在query里实现最基本的selector查询，比如ID、class、tag、属性，之后用户可以自定义selector添加到查询函数当中，来实现自己特定的查询需求，从这点出发，改写了之前所写的query代码（之前的query.js），目前它只集合了ID、class、tag、属性选择器（或者也可以干脆连这些使用者都可以重新定义自己的功能函数，自己来实现，DIY很爽~），其他的自定义选择器都可以自己DIY，并且编写它的实现方式（留给使用者更多的编写底层代码的空间，爱怎么实现就怎么实现，方法是多样的），比如：给selector添加“:first”和“:l”来实现CSS3中的:first-child和:last-child的功能： [javascript] //q:表示当前的selector，比如“div p:first”，就是div和p:first，使用split通过空格切分的单个selector //p:表示是上一级查询的结果，是数组类型的。 query.config.addSelector(&#34;:first&#34;,function(q,p){ var tagName = q.split(&#34;:first&#34;)[0], returnEl = [], index=0, &#8230; <a href="http://www.ilovejs.net/archives/1129" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
“松散耦合”、“颗粒度”是相对于javascript库或者javascript框架来说的，它涉及的概念和包含的知识是很多的，而其中之一，就是说javascript库或者框架从整理来看是容易拆分，也容易自定义的组合，来实现特定需求的功能。之前有很多说法说YUI的编写方法才更接近于javascript的本质，虽然上手的门槛很高，但是对于一个真正的javascript程序员来说，反而更值得；而jQuery似乎另类了，改变了普通的编写javascript的编写方式，虽然说它封装的很好，“用最少的代码实现复杂的功能”，但是它的可读性就很差了，虽然门槛很低，毫无javascript基础的程序员在看了它的API文档之后都能够利用它写出很多丰富的效果。但是，作为程序员，这样下去行吗？
</p>
<p>
<em>jQuery是毒药</em> &#8212;&#8212; 很多人都这么说。本人也举得，从一个程序员的成长来看，jQuery是弊大于利。我们更应该做的是学习它的原理和架构，而不是拿来用而已。
</p>
<p>
一个很经常会发生的问题：我只需要用到一个javascript库中的几个方法，却需要加载整个库的体积，而整个库封装的又十分复杂，拆分起来十分繁琐，怎么办？自己写呗……
</p>
<p>
一个javascript库的本意虽然说是为了提高开发效率、解决浏览器的兼容性问题、统一开发规范以及解决安全隐患等等。但是在设计javascript库的时候，我们是不是应该多留多点空间给使用者去DIY它的具体的功能，让使用者多点接触到javascript的本质，以及非常容易的缩减库的体积呢？就从这几点出发，YUI3是比较符合“松散耦合”、“颗粒度”的原则的，虽然说jQuery可以通过fn方法来扩展，但都是基于它整个已经封装好的库来说的。但是YUI3也有它的缺点：学习成本高、整体体积庞大、可能一步小心在use方法里多加载几个文件，或者使用”*”，那么需要异步加载的js文件也是很多的、以及它内部组件之间的依赖关系也是比较复杂的。
</p>
<p>
为了说明我的想法，首先从我编写的query鸡查询函数（目前还没完善，先拿来做例子）开始说起，我的想法是：只在query里实现最基本的selector查询，比如ID、class、tag、属性，之后用户可以自定义selector添加到查询函数当中，来实现自己特定的查询需求，从这点出发，改写了之前所写的query代码（之前的<a  href="http://www.ilovejs.net/lab/query/query.js">query.js</a>），目前它只集合了ID、class、tag、属性选择器（或者也可以干脆连这些使用者都可以重新定义自己的功能函数，自己来实现，DIY很爽~），其他的自定义选择器都可以自己DIY，并且编写它的实现方式（留给使用者更多的编写底层代码的空间，爱怎么实现就怎么实现，方法是多样的），比如：给selector添加“:first”和“:l”来实现CSS3中的:first-child和:last-child的功能：
</p>
<p>[javascript]<br />
//q:表示当前的selector，比如“div p:first”，就是div和p:first，使用split通过空格切分的单个selector<br />
//p:表示是上一级查询的结果，是数组类型的。<br />
query.config.addSelector(&quot;:first&quot;,function(q,p){<br />
  var tagName = q.split(&quot;:first&quot;)[0],<br />
	  returnEl = [],<br />
	  index=0,<br />
	  tmp=null;<br />
  for(var i=0,l=p.length;i&lt;l;i++){<br />
	(tmp=query(tagName,[p[i]])) &amp;&amp; (returnEl[index++]=tmp[0]);<br />
  }<br />
  return returnEl;<br />
});<br />
///////////////////////////////////////////////////////////<br />
query.config.addSelector(&quot;:l&quot;,function(q,p){<br />
  var tagName = q.split(&quot;:l&quot;)[0],<br />
	  returnEl = [],<br />
	  index=0,<br />
	  tmp=null;<br />
  for(var i=0,l=p.length;i&lt;l;i++){<br />
	(tmp=query(tagName,[p[i]])) &amp;&amp; (returnEl[index++]=tmp[tmp.length-1]);<br />
  }<br />
  return returnEl;<br />
});<br />
[/javascript]</p>
<p>
通过这样的方式，使得core核心代码尽可能的小，可扩展性强，同时也提供给使用者更多的编码空间，了解javascript这门语言的核心知识。目前经过压缩过后的<a  href="/lab/query/query2-min.js">query2-min.j</a>s和未压缩的<a  href="/lab/query/query2.js">query2.js</a>提供浏览。并附带实例：《<a  href="/lab/query/query2.html">点点看呗</a>》
</p>
<p>
扯谈完毕，欢迎拍砖~</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1129/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>在IE中模拟Worker</title>
		<link>http://www.ilovejs.net/archives/1118</link>
		<comments>http://www.ilovejs.net/archives/1118#comments</comments>
		<pubDate>Sat, 07 Aug 2010 13:50:29 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[性能优化]]></category>
		<category><![CDATA[Worker]]></category>
		<category><![CDATA[多线程]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1118</guid>
		<description><![CDATA[2010-8-8 update:在IE8下的eval是不支持下面两种的用法的，很杯具，都会提示“对象不支持此属性或方法”的错误。 [javascript] //第一： eval(&#34;onmessage=function(str){alert(str);}&#34;); onmessage(&#34;shllo&#34;); //第二： var s = document.createElement(&#34;script&#34;),h=document.getElementsByTagName(&#34;head&#34;)[0]; s.text=&#34;onmessage=function(str){alert(str);}&#34;; h.appendChild(s); onmessage(&#34;hello&#34;); [/javascript] 说到这个，还发现一点很容易造成失误的地方：在浏览器解析过的script中的代码，浏览器不会重新对该script标签内的行内脚本、外联脚本执行，就算是重新给script标签定义行内脚本或者修改它的src来链接到其他的javascript脚本，浏览器都不会重新解析。 &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;- 提IE8 eval的兼容性分界线 &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211; &#8230; <a href="http://www.ilovejs.net/archives/1118" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
<strong>2010-8-8 update:</strong>在IE8下的eval是不支持下面两种的用法的，很杯具，都会提示“对象不支持此属性或方法”的错误。
</p>
<p>[javascript]<br />
//第一：<br />
eval(&quot;onmessage=function(str){alert(str);}&quot;);<br />
onmessage(&quot;shllo&quot;);<br />
//第二：<br />
var s = document.createElement(&quot;script&quot;),h=document.getElementsByTagName(&quot;head&quot;)[0];<br />
s.text=&quot;onmessage=function(str){alert(str);}&quot;;<br />
h.appendChild(s);</p>
<p>onmessage(&quot;hello&quot;);<br />
[/javascript]</p>
<p><p>
说到这个，还发现一点很容易造成失误的地方：在浏览器解析过的script中的代码，浏览器不会重新对该script标签内的行内脚本、外联脚本执行，就算是重新给script标签定义行内脚本或者修改它的src来链接到其他的javascript脚本，浏览器都不会重新解析。
</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;- 提IE8 eval的兼容性分界线 &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;
</p>
<p>
从上一篇文章《<a  href="http://www.ilovejs.net/archives/1079">Web Worker浅析</a>》中，我们了解到Worker的思维是跟Ajax类似的，包括它也不支持跨域调用javascript文件，这说明底层的数据交互还是跟Ajax的模式类似（也有可能就是使用了Ajax的方式）。但是由于IE8及以下版本都不支持Worker，所以IE就不能充分利用Worker的优点来优化浏览器执行javascript代码的性能了。但是既然Worker跟Ajax类似，那么就让IE使用Ajax的方式来实现吧，这也不是不行的。
</p>
<p>
在IE中实现Worker机制，一个比较棘手的问题是postMessage、onmessage在主页面和Worker之间的调用问题，从代码上看，主页面是通过Worker类的实例化对象来调用postMessage、onmessage，而Worker里是直接声明和调用。所以在IE里，就可以模拟Worker的操作方式了。下面是我在IE下实现的方式：
</p>
<ol>
<li>在IE下重新定义Worker类，并且带有一个postMessage方法，这样就的话不会跟支持Worker的浏览器相冲突</li>
<li>使用Ajax的方式来加载外联的javascript文件，并通过eval执行返回的代码</li>
<li>通过一个全局的字面量对象，来实现两个文件之间的数据传输</li>
<li>不能改变标准的Worker类的编写方式，这个是一定要做到的</li>
</ol>
<p>从上面的几点思路出发，编写了下面的实现代码：<br />
[javascript]<br />
(function(g){<br />
   if(!document.all) return;</p>
<p>   var xhr=function(){<br />
     var x = null;<br />
     try{<br />
	   x = new ActiveXObject(&quot;Msxml2.XMLHTTP&quot;);<br />
	 }catch(e){<br />
       x = new ActiveXObject(&quot;Microsoft.XMLHTTP&quot;);<br />
	 }<br />
	 return x;<br />
   }</p>
<p>   g.postMessage = function(data){<br />
     g._evt_.data = data;<br />
   }</p>
<p>   var Worker = function(url){<br />
     this.url = url;<br />
   }</p>
<p>   Worker.prototype={<br />
     postMessage:function(data){<br />
       g._evt_={};<br />
	   g._evt_.data=data;<br />
	   var x=xhr(),t=this;<br />
	   x.open(&quot;GET&quot;,this.url,true);<br />
	   x.onreadystatechange=function(){<br />
	     if(x.readyState === 4 &amp;&amp; (x.status === 304 || x.status === 200)){<br />
                   //直接使用eval(x.responseText)在IE8下会提示错误，很奇怪，可能跟eval函数有关了<br />
                   //为此不得不使用这种不太牢固的方法<br />
		   eval(x.responseText.replace(&quot;onmessage&quot;,&quot;var onmessage&quot;));<br />
		   onmessage(g._evt_); //执行Worker中定义的onmessage方法<br />
		   t.onmessage(g._evt_); //执行主页面中的onmessage方法<br />
		   g._evt_ = null;<br />
		 }<br />
	   }<br />
	   x.send();<br />
	 }<br />
   }<br />
   g.Worker = Worker;<br />
})(this);<br />
[/javascript]<br />
在使用上有一点得注意，虽然在代码上没改变，但是在主页面中postMessage和onmessage的顺序得保持：先写onmessage、接着写postMessage方法，主要是为了在IE下能兼容。比如：<br />
[javascript]<br />
var worker = new Worker(&quot;js.js&quot;);</p>
<p>worker.onmessage = function(evt){<br />
  alert(evt.data);<br />
}<br />
 //注意postMessage方法一定要在onmessage后面声明，否则会导致代码只会有一次有效。<br />
worker.postMessage(&quot;supersha&quot;);<br />
[/javascript]</p>
<p>
到目前为止，测试还算良好，《<a  href="http://www.ilovejs.net/lab/ieworker/">测试页面</a>》，在各个浏览器下都能够跑起来。
</p>
<p>
目前这个只是个简单的实现方案，代码上还是比较简单的，有待进一步的完善……</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1118/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>flush()和ob_flush();flush()组合的差别</title>
		<link>http://www.ilovejs.net/archives/1057</link>
		<comments>http://www.ilovejs.net/archives/1057#comments</comments>
		<pubDate>Wed, 28 Jul 2010 11:25:10 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[性能优化]]></category>
		<category><![CDATA[flush]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1057</guid>
		<description><![CDATA[2010-7-29 Updates: 如果将render解析为“呈现”，即是将元素显示到视窗中，那么Nicholas的说法在大部分浏览器下是正确的，经过下面使用PHP方式的测试，在没有将闭合标签加载下来之前，页面无法显示h1标签内容，但是IE除外，它仍然显示内容和应用样式。 同时还有一点需要说明的是：一些文章说在head和body之间插入flush()方法来尽早的输出head的内容，以至于尽快的下载样式资源，这也是有一定道理的，但是由于刷新输出的head内容是不可见的，所以页面上还是会一片空白，等待内容的呈现。所以比较合理的做法是将内容分块，或者将页面内容分为head、body、footer等俺顺序使用flush刷新输出，这样就使得有一个比较流畅的页面显示效果。 本人的blog正在这样实践着…… &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;纠正分界线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212; 在Nicholas的一个PPT中看到了这句话“The browser won&#8217;t render a block-level element inside of &#60;body&#62; until the closing tag &#8230; <a href="http://www.ilovejs.net/archives/1057" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
<em>2010-7-29 Updates:</em>
</p>
<p>如果将render解析为“呈现”，即是将元素显示到视窗中，那么Nicholas的说法在大部分浏览器下是正确的，经过下面使用PHP方式的测试，在没有将闭合标签加载下来之前，页面无法显示h1标签内容，但是IE除外，它仍然显示内容和应用样式。</p>
<p>
同时还有一点需要说明的是：一些文章说在head和body之间插入flush()方法来尽早的输出head的内容，以至于尽快的下载样式资源，这也是有一定道理的，但是由于刷新输出的head内容是不可见的，所以页面上还是会一片空白，等待内容的呈现。所以比较合理的做法是将内容分块，或者将页面内容分为head、body、footer等俺顺序使用flush刷新输出，这样就使得有一个比较流畅的页面显示效果。
</p>
<p>
本人的blog正在这样实践着……
</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;纠正分界线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</p>
<p>
在Nicholas的一个PPT中看到了这句话“The browser won&#8217;t render a block-level element inside of &lt;body&gt;<br />
until the closing tag has been received”，意思就是“在body中，浏览器在一个块级元素的闭合标签未加载下来之前不会渲染该元素”，第一次看到这样的说法，感到很奇妙，到底是不是真的呢？
</p>
<p>
<del datetime="2010-07-28T16:51:27+00:00">首先，使用javasript来进行测试，在一个块级元素中嵌套一个脚本，来获取该块级元素的innerHTML，《<a  href="/lab/flush/js.html">测试用例</a>》，测试结果上面的说法错误。</del>
</p>
<p>
<del datetime="2010-07-28T16:51:27+00:00">接着测块级元素的style，使用js输出块级元素的style属性值，《<a  href="/lab/flush/style.html">测试用例</a>》，测试结果上面的说法错误。</del>
</p>
<p>
接着使用PHP的方式，在块级元素的闭合标签前面加上<code>&lt;php flush(); sleep(3); ?&gt;</code>，来查看是否会刷新输出内容，测试结果就是文章标题中所说明的问题，使用flush()和ob_flush();flush()组合的结果是不同的，并且在不同的浏览器下行为又有所不同。《<a  href="/lab/flush/flush2.php">flush()</a>》，《<a  href="/lab/flush/flush.php">ob_flush();flush()</a>》。
</p>
<p>
PHP的测试结果为：使用flush()的形式的时候，Opera、Chrome、Safari、IE并没有在flush执行的时候刷新输出前面的内容；使用ob_flush();flush()组合的时候，Opera、Chrome、Safari、IE可以刷新输出前面的内容，但是这里又有个小插曲，IE可以输出元素闭合标签之前的内容，并可以渲染样式，但是Opera、Chrome、Safari只输出该元素之前的内容，该元素内的文本内容不会刷新输出。或许大家没有看到我提及Firefox浏览器的情况，经过测试，Firefox杯具的是两种形式都不会刷新输出内容，需要等到整个HTML文档加载完成才显示页面。为此，应该避免下面的情况：
</p>
<p>[html]<br />
  &lt;div&gt;Hello baby,www.ilovejs.net is here&#8230;&lt;?php ob_flush();flush(); ?&gt;&lt;/div&gt;<br />
  &lt;!&#8211;或者&#8211;&gt;<br />
  &lt;div&gt;Hello baby,www.ilovejs.net is here&#8230;&lt;?php flush(); ?&gt;&lt;/div&gt;<br />
[/html]</p>
<p>
经过这些测试，可以得到明显的结论：在输出刷新方面，尽量使用ob_flush();flush()组合，并且避免在HTML标签的闭合标签之前刷新输出。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1057/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>浅析Memoization</title>
		<link>http://www.ilovejs.net/archives/1040</link>
		<comments>http://www.ilovejs.net/archives/1040#comments</comments>
		<pubDate>Tue, 13 Jul 2010 08:27:14 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[性能优化]]></category>
		<category><![CDATA[lazy definition]]></category>
		<category><![CDATA[Memoization]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1040</guid>
		<description><![CDATA[Memoization，简单的说就是优化计算机的性能，缓存那些重复性的函数操作和计算，使得第一次之后的调用可以直接从缓存中得到结果，而无需重新计算和运行复杂、费时的函数。这个跟Lazy Definition的原理是比较相似的，Lazy Definition主要是对函数进行重复定义，避免浏览器检测等恶心的事情。在javascript里实现Memoization的技术，Keith Gaughan做了相关的叙述：Memoization in JavaScript。特别是它对Fibonacci的优化让我特别的玩味。 对于Fibonacci普通的实现方式是： [javascript] //这个性能不咋的，函数调用太频繁了 function Fib(n) { if (n &#60; 2) { return n;} return &#8230; <a href="http://www.ilovejs.net/archives/1040" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
<a  href="http://en.wikipedia.org/wiki/Memoization">Memoization</a>，简单的说就是优化计算机的性能，缓存那些重复性的函数操作和计算，使得第一次之后的调用可以直接从缓存中得到结果，而无需重新计算和运行复杂、费时的函数。这个跟<a  href="http://www.ilovejs.net/archives/126">Lazy Definition</a>的原理是比较相似的，L<a  href="http://www.ilovejs.net/archives/126">azy Definition</a>主要是对函数进行重复定义，避免浏览器检测等恶心的事情。在javascript里实现Memoization的技术，<a  href="http://talideon.com">Keith Gaughan</a>做了相关的叙述：<a  href="http://talideon.com/weblog/2005/07/javascript-memoization.cfm">Memoization in JavaScript</a>。特别是它对Fibonacci的优化让我特别的玩味。
</p>
<p>
对于Fibonacci普通的实现方式是：
</p>
<p>[javascript]<br />
//这个性能不咋的，函数调用太频繁了<br />
function Fib(n) {<br />
    if (n &lt; 2) { return n;}<br />
    return Fib(n &#8211; 1) + Fib(n &#8211; 2);<br />
}<br />
[/javascript]<br />
而<a  href="http://talideon.com">Keith Gaughan</a>对它的实现方式用Memoization进行了优化：<br />
[javascript]<br />
var IterMemoFib = function() {<br />
    var cache = [1, 1];<br />
    var fib = function(n) {<br />
        if (n &gt;= cache.length) {<br />
            for (var i = cache.length; i &lt;= n; i++) {<br />
                //这句代码很耐人寻味，还有循环的方式<br />
                cache[i] = cache[i - 2] + cache[i - 1];<br />
            }<br />
        }<br />
        return cache[n];<br />
    }<br />
    return fib;<br />
}();<br />
[/javascript]</p>
<p>
上面关于Fibonacci的优化，就是使用了Memoization技巧，将上一步的加法操作缓存起来，用户循环中下一轮的递增。缓存计算结果是Memorize应用最多的需求，避免了对计算结果的重复性计算，但是如果计算结果是动态的呢，或者说你想获取动态修改过后的计算结果呢？ 比如DOM的length属性，这个是易变的，这个时候就不能去获取缓存的结果了，需要重复计算。
</p>
<p><span id="more-1040"></span></p>
<p>
下面先来看一段<a href="http://blog.stevenlevithan.com/">Flagrant Badassery</a>编写的一个Timed Memoization函数，一方面用于缓存结果，另一方面则是在时间参数指定的时间间隔里清除掉缓存的结果：
</p>
<p>[javascript]<br />
var memorize=function(fn,timer){<br />
  var obj = {};<br />
  return function(){<br />
    var key = [].join.call(arguments,&quot;$&quot;);<br />
	if(timer){<br />
	     setTimeout(function(){delete obj[key];},timer);<br />
	}<br />
        //这个返回方式本人进行了一点修改<br />
	return (key in obj) ? obj[key] : obj[key] = fn.apply(this,arguments);<br />
  }<br />
}<br />
[/javascript]<br />
上面的代码思路不错，在指定的时间之后清楚缓存结果，但是我觉得这个思路还可以用于更多场合，比如清除对象，及时断开作用域链，使得无用的对象可以及时的回收占用的内存。基于这个思路，本人做了些修修补补，编写了下面的几个方法：<br />
[javascript]<br />
//将memorize函数生成的函数也缓存起来<br />
var memorize2 = function(fn,timer){<br />
  var key = [].join.call(arguments,&quot;$&quot;),obj={};<br />
  return memorize2[key] ? memorize2[key] : (memorize2[key] = function(){<br />
    var k = [].join.call(arguments,&quot;$&quot;);<br />
	if(timer){<br />
	  setTimeout(function(){delete obj[k];delete memorize2[key];},timer);<br />
	}<br />
	return obj[k] ? obj[k] : (obj[k] = fn.apply(this,arguments);<br />
  }<br />
}<br />
[/javascript]<br />
对于上面说到的，如果有些计算结果是会动态改变的，这时候就该在需要的时候进行重复计算，为此，编写了一个Function扩展，借鉴上面Timed Momeization的思路：<br />
[javascript]<br />
Function.prototype.memorize = function(timer){<br />
  var obj = {}, that = this, key = &quot;$&quot;;<br />
  return function(flag){<br />
    var args = [].slice.call(arguments,1) || [];<br />
	if(flag){<br />
	  return obj[key] = that.apply(this,args);<br />
	}<br />
	key = [].join.call(arguments,&quot;$&quot;);<br />
	if(timer){<br />
	  setTimeout(function(){delete obj[key];},timer);<br />
	}<br />
	return obj[key] ? obj[key] : obj[key] = that.apply(this,args);<br />
  }<br />
}<br />
[/javascript]</p>
<p>
如上面代码所示，使用memorize返回的函数中带有一个flag参数，如果不存在这个参数或者设置为false，则从缓存中去获取上一步缓存的结果，如果设置为true，则重复计算、并重新设置缓存的值。通过这样的实现方式，既可以通过参数的形式来判断获取动态改变的结果，也可以在不需要动态改变参数的时候获取缓存的结果，《<a  href="http://www.ilovejs.net/lab/memorize/">测试用例</a>》。使用方式如下：
</p>
<p>[javascript]<br />
var length = function(){<br />
  return div.getElementsByTagName(&quot;p&quot;).length;<br />
}.memorize();<br />
[/javascript]</p>
<p>
为此，Memoization对于一些静态的计算结果进行缓存，从而起到优化代码性能的作用；但是对于会动态改变的计算结果，则需要另当别论了。
</p>
<p>更多的参考文章：《<a  href="http://osteele.com/archives/2006/04/javascript-memoization">ONE-LINE JAVASCRIPT MEMOIZATION</a>》，《<a  href="http://talideon.com/weblog/2005/07/javascript-memoization.cfm">Memoization in JavaScript</a>》，《<a  href="http://blog.stevenlevithan.com/archives/timed-memoization">Timed Memoization</a>》，《<a  href="http://www.ilovejs.net/archives/126">Javascript的Lazy Definition Pattern</a>》</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1040/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>用于测试页面Repaint的firebug扩展 &#8212; Repeat Test</title>
		<link>http://www.ilovejs.net/archives/1020</link>
		<comments>http://www.ilovejs.net/archives/1020#comments</comments>
		<pubDate>Mon, 05 Jul 2010 19:43:45 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[性能优化]]></category>
		<category><![CDATA[firebug]]></category>
		<category><![CDATA[Firefox]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=1020</guid>
		<description><![CDATA[归家了，博客都没怎么更新，感觉有些不适应了。这几天忙里偷闲，研究了下firebug扩展的开发原理，倒弄了两三天，firebug的架构也确实比较复杂，而且发现Firefox下的扩展在开发中编写js代码并没有想象中的容易，平时认为合理的js代码，在Firefox的插件里跑起来，却总是会出现诸多错误，很纠结。仔细查看了firebug的源码中的xul文件，觉得firebug的架构和方法调用方式，也确实值得借鉴，语意化十足：利用xul文件来规划布局，js实现功能，css实现样式布局，properties格式的文件来储存文字信息…… 《Repaint 跟踪浏览器的渲染》从这篇文章中了解到，原来Firefox还有一个独有的事件：MozAfterPaint供我们来测试页面Repaint的数据，这个事件的具体使用方式和参数设置可以查看前面给出链接中Mozilla的官方叙述。PJhome网站中给出的例子是需要通过使用Greasemonkey来自定义一个脚本，我感觉这有诸多不便：不便于操作；开始和结束等方面的不变……为此，我将这个功能集成到firebug下，基本上web开发人员都会安装firebug，所以倒是便利了许多。下面就来说说Repaint Test的具体使用方式： 首先用Firefox3.5以上的版本（因为MozAfterPaint事件是在3.5版本之后才受支持的）下载Repaint Test文件：Repaint Test，直接点击链接就可以安装了。 打开firebug主界面，其中就有一个叫“Repaint Test”的面板，点击它，就出现了它的操作按钮组： Repaint Test面板下面有“Self start record”、“Start”、“Stop and Show”、“Clear”按钮，同时面板右边还有下拉菜单，提供了“Configuration”、“Zoom（文字大小）”、“Help”等功能。顾名思义，Configuration是用于配置扩展内部的一些属性。 “Self start record”按钮用于在页面加载后，在设置的时间内自动开始记录Repaint区域数据；“Start”按钮用于手动设置记录Repaint的开始；“Stop and Show”用于停止记录Repaint区域数据并显示Repaint区域（红色高亮显示），这里有定时器来显示每一个记录的Repaint数据。“Clear”按钮用于清空输出内容。 &#8230; <a href="http://www.ilovejs.net/archives/1020" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
归家了，博客都没怎么更新，感觉有些不适应了。这几天忙里偷闲，研究了下firebug扩展的开发原理，倒弄了两三天，firebug的架构也确实比较复杂，而且发现Firefox下的扩展在开发中编写js代码并没有想象中的容易，平时认为合理的js代码，在Firefox的插件里跑起来，却总是会出现诸多错误，很纠结。仔细查看了firebug的源码中的xul文件，觉得firebug的架构和方法调用方式，也确实值得借鉴，语意化十足：利用xul文件来规划布局，js实现功能，css实现样式布局，properties格式的文件来储存文字信息……
</p>
<p>
《<a  href="http://www.pjhome.net/article/Javascript/browser_repaint_reflow.htm">Repaint 跟踪浏览器的渲染</a>》从这篇文章中了解到，原来Firefox还有一个独有的事件：<a  href="https://developer.mozilla.org/en/Gecko-Specific_DOM_Events">MozAfterPaint</a>供我们来测试页面Repaint的数据，这个事件的具体使用方式和参数设置可以查看前面给出链接中Mozilla的官方叙述。<a  href="http://www.pjhome.net">PJhome</a>网站中给出的例子是需要通过使用Greasemonkey来自定义一个脚本，我感觉这有诸多不便：不便于操作；开始和结束等方面的不变……为此，我将这个功能集成到firebug下，基本上web开发人员都会安装firebug，所以倒是便利了许多。下面就来说说Repaint Test的具体使用方式：
</p>
<ol>
<li>首先用Firefox3.5以上的版本（因为MozAfterPaint事件是在3.5版本之后才受支持的）下载Repaint Test文件：<a  href="http://www.ilovejs.net/download/Repaint Test 0.0.1.xpi">Repaint Test</a>，直接点击链接就可以安装了。</li>
<li>打开firebug主界面，其中就有一个叫“Repaint Test”的面板，点击它，就出现了它的操作按钮组：<br />
<img src="http://www.ilovejs.net/wp-content/uploads/2010/07/repaint1.png" alt="" title="repaint1" width="639" height="81" class="alignnone size-full wp-image-1021" /><br />
Repaint Test面板下面有“Self start record”、“Start”、“Stop and Show”、“Clear”按钮，同时面板右边还有下拉菜单，提供了“Configuration”、“Zoom（文字大小）”、“Help”等功能。顾名思义，Configuration是用于配置扩展内部的一些属性。<br />
<img src="http://www.ilovejs.net/wp-content/uploads/2010/07/repaint2.png" alt="" title="repaint2" width="374" height="32" class="alignnone size-full wp-image-1022" />
</li>
<li>“Self start record”按钮用于在页面加载后，在设置的时间内自动开始记录Repaint区域数据；“Start”按钮用于手动设置记录Repaint的开始；“Stop and Show”用于停止记录Repaint区域数据并显示Repaint区域（红色高亮显示），这里有定时器来显示每一个记录的Repaint数据。“Clear”按钮用于清空输出内容。
</li>
<li>在这里需要明白的是：“Self start record”和“Stop and Show”按钮内部都设定了定时器，不过间隔时间可以自定义，在Configuration弹出框里可以设置。但是最后的展示输出Repaint区域数据都需要点击“Stop and Show”来完成。<br />
<img src="http://www.ilovejs.net/wp-content/uploads/2010/07/repaint3.png" alt="" title="repaint3" width="366" height="161" class="alignnone size-full wp-image-1023" /><br />
<img src="http://www.ilovejs.net/wp-content/uploads/2010/07/repaint4.png" alt="" title="repaint4" width="297" height="169" class="alignnone size-full wp-image-1029" />
</li>
<li>还有，输出的每一项Repaint的区域数据，都可以点击，再现Repaint区域的高亮效果。</li>
</ol>
<p>
在<a  href="http://www.pjhome.net">PJhome</a>中，还介绍了IE9提供了更多开放的接口供前端开发人员进行性能测试：《<a  href="http://www.pjhome.net/article/Javascript/IE9_msPerformance.htm">IE9允许前端开发获取到页面性能数据</a>》，Very perfect！！但是IE系列总会有很多让人抹汗的地方，IE9的这套接口能否满足以后页面性能测试的需要，还有待测试和考验。
</p>
<p>
最后，欢迎大家对这个Repaint Test扩展进行测试和提出更好的建议，尽力去完善它的功能和使它在使用上更加的简便……</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/1020/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Script DOM Element加载js文件的延伸</title>
		<link>http://www.ilovejs.net/archives/986</link>
		<comments>http://www.ilovejs.net/archives/986#comments</comments>
		<pubDate>Fri, 25 Jun 2010 18:43:44 +0000</pubDate>
		<dc:creator>Supersha</dc:creator>
				<category><![CDATA[性能优化]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Script DOM Element]]></category>
		<category><![CDATA[图片]]></category>

		<guid isPermaLink="false">http://www.ilovejs.net/?p=986</guid>
		<description><![CDATA[Script DOM Element动态加载js可以使得js文件跟其他资源并行加载并异步执行，这是我们都知道的事实。但是有一点，或许有些人没有想到，js脚本在何时才会开始加载？ 话说多了不足为信，看一个简单的测试：《测试js何时开始加载（用firebug查看HTTP瀑布图，或者HTTPWatch、Inspection等等均可）》，代码示例如下 [javascript] var s = document.createElement(&#34;script&#34;); s.setAttribute(&#34;src&#34;,&#34;test.js&#34;); var l =document.createElement(&#34;link&#34;); l.setAttribute(&#34;href&#34;,&#34;/wp-content/c/style.css&#34;); l.setAttribute(&#34;rel&#34;,&#34;stylesheet&#34;); var img = new Image(); &#8230; <a href="http://www.ilovejs.net/archives/986" class="more-link">了解更多</a>]]></description>
			<content:encoded><![CDATA[<p>
Script DOM Element动态加载js可以使得js文件跟其他资源并行加载并异步执行，这是我们都知道的事实。但是有一点，或许有些人没有想到，js脚本在何时才会开始加载？
</p>
<p>
话说多了不足为信，看一个简单的测试：《<a  href="/lab/load-order/test.html">测试js何时开始加载</a>（用firebug查看HTTP瀑布图，或者HTTPWatch、Inspection等等均可）》，代码示例如下
</p>
<p>[javascript]<br />
var s = document.createElement(&quot;script&quot;);<br />
s.setAttribute(&quot;src&quot;,&quot;test.js&quot;);</p>
<p>var l =document.createElement(&quot;link&quot;);<br />
l.setAttribute(&quot;href&quot;,&quot;/wp-content/c/style.css&quot;);<br />
l.setAttribute(&quot;rel&quot;,&quot;stylesheet&quot;);</p>
<p>var img = new Image();<br />
img.setAttribute(&quot;src&quot;,&quot;/wp-content/uploads/2010/06/performance.png&quot;);<br />
//document.body.appendChild(img);<br />
document.body.appendChild(l);<br />
document.body.insertBefore(s,document.body.lastChild);<br />
[/javascript]</p>
<p>
通过上面的测试发现：图片先加载，之后是js，最后是css文件。但是看上面的代码，图片并没有插入到文档中，但是它还是加载了；虽然js先于图片声明，但是却在图片之后加载；CSS虽然后于js声明，但是先于js加载。
</p>
<p>
这就有意思了，通过上面的测试说明：使用new Image声明的图片，在设置它的src属性之后就会开始加载；js和css文件在插入到文档之后才开始加载。通过这个特点，我们在性能优化方面就可以再总结几点想法了：
</p>
<ol>
<li>通过使用Script DOM Element的方式加载js的时候，虽然说是可以同其他资源并行加载和异步执行，但是如果加载的js可以在页面加载完成之后才需要起作用的，可以在&lt;/body&gt;前面来声明并插入到页面中，从而可以多让其他资源并行加载，而js最后加载并执行，加快页面的加载速度，这样的话将js插入到head和document.body都一样的效果。</li>
<li>同样使用Link DOM Element的方式加载css文件的时候（如果一定要这样做的话），因为样式表关系到整个页面的布局和样式渲染，所以它需要尽早的被加载进来并开始渲染，以免造成页面内容显示的延迟和IE下“白屏”的问题。</li>
<li>在优化图片加载的需求上，虽然图片加载是并行的，但是浏览器并行加载资源的数目是受到限制的，对于那些不是在浏览器第一屏（打开网页时在浏览器视窗内看到的内容）看到的图片、图片Tab组件、图片列表等等，可是使用上面的方式动态来插入，在页面其他重要的内容和资源都加载完毕的时候，其次的图片动态的插入，使得浏览器开始加载这些的图片。对于加快页面的显示速度，这也是不错的方式。</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.ilovejs.net/archives/986/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<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>
	</channel>
</rss>

