<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-294379627880145984</id><updated>2011-04-22T02:37:01.104+08:00</updated><category term='生活'/><category term='其他技术'/><category term='转贴'/><category term='css'/><category term='javascript'/><category term='java'/><category term='web2.0'/><category term='rails'/><category term='ide'/><title type='text'>netfishx's matrix</title><subtitle type='html'>I love coding!!!</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://netfishx.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/294379627880145984/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://netfishx.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>netfishx</name><uri>http://www.blogger.com/profile/15593804318935689524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>15</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-294379627880145984.post-8518118053614381651</id><published>2007-02-25T15:43:00.000+08:00</published><updated>2007-02-25T15:44:55.972+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><title type='text'>排序</title><content type='html'>sun的官方实现：&lt;br /&gt;   private static void sort1(int x[], int off, int len) {&lt;br /&gt;   // Insertion sort on smallest arrays&lt;br /&gt;   if (len &lt; i="off;" for="" int="" j="i;"&gt;off &amp;&amp;amp;amp; x[j-1]&gt;x[j]; j--)&lt;br /&gt;           swap(x, j, j-1);&lt;br /&gt;       return;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   // Choose a partition element, v&lt;br /&gt;   int m = off + (len &gt;&gt; 1);       // Small arrays, middle element&lt;br /&gt;   if (len &gt; 7) {&lt;br /&gt;       int l = off;&lt;br /&gt;       int n = off + len - 1;&lt;br /&gt;       if (len &gt; 40) {        // Big arrays, pseudomedian of 9&lt;br /&gt;       int s = len/8;&lt;br /&gt;       l = med3(x, l,     l+s, l+2*s);&lt;br /&gt;       m = med3(x, m-s,   m,   m+s);&lt;br /&gt;       n = med3(x, n-2*s, n-s, n);&lt;br /&gt;       }&lt;br /&gt;       m = med3(x, l, m, n); // Mid-size, med of 3&lt;br /&gt;   }&lt;br /&gt;   int v = x[m];&lt;br /&gt;&lt;br /&gt;   // Establish Invariant: v* (&lt;v)*&gt;v)* v*&lt;br /&gt;   int a = off, b = a, c = off + len - 1, d = c;&lt;br /&gt;   while(true) {&lt;br /&gt;       while (b &lt;= c &amp;&amp;amp; x[b] &lt;= v) {         if (x[b] == v)             swap(x, a++, b);         b++;         }         while (c &gt;= b &amp;&amp;amp; x[c] &gt;= v) {&lt;br /&gt;       if (x[c] == v)&lt;br /&gt;           swap(x, c, d--);&lt;br /&gt;       c--;&lt;br /&gt;       }&lt;br /&gt;       if (b &gt; c)&lt;br /&gt;       break;&lt;br /&gt;       swap(x, b++, c--);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   // Swap partition elements back to middle&lt;br /&gt;   int s, n = off + len;&lt;br /&gt;   s = Math.min(a-off, b-a  );  vecswap(x, off, b-s, s);&lt;br /&gt;   s = Math.min(d-c,   n-d-1);  vecswap(x, b,   n-s, s);&lt;br /&gt;&lt;br /&gt;   // Recursively sort non-partition-elements&lt;br /&gt;   if ((s = b-a) &gt; 1)&lt;br /&gt;       sort1(x, off, s);&lt;br /&gt;   if ((s = d-c) &gt; 1)&lt;br /&gt;       sort1(x, n-s, s);&lt;br /&gt;   }&lt;/v)*&gt;&lt;/len+off;&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/294379627880145984-8518118053614381651?l=netfishx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://netfishx.blogspot.com/feeds/8518118053614381651/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=294379627880145984&amp;postID=8518118053614381651' title='1 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/294379627880145984/posts/default/8518118053614381651'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/294379627880145984/posts/default/8518118053614381651'/><link rel='alternate' type='text/html' href='http://netfishx.blogspot.com/2007/02/blog-post_25.html' title='排序'/><author><name>netfishx</name><uri>http://www.blogger.com/profile/15593804318935689524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-294379627880145984.post-1685829454918183342</id><published>2007-02-01T09:26:00.000+08:00</published><updated>2007-02-01T09:29:13.483+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='web2.0'/><category scheme='http://www.blogger.com/atom/ns#' term='转贴'/><title type='text'>丢谁的人</title><content type='html'>Google又惹事了。这一次是一个叫佛祖也淫笑的热血愤青惊异地发现，在GoogleEarth里面沈阳的地名变成了日文，而且标注的都是伪满时期使用的地名。一石激起千层粪，&lt;a href="http://news.163.com/07/0131/10/365IF4J5000120GU.html" target="_blank"&gt;这个消息&lt;/a&gt;引来了网上又一波对小日本的鄙视和攻击，同时也引发了又一轮gfans和百度拥趸的对战。&lt;br /&gt;&lt;br /&gt;其实愤青们应该理性地想想这事，究竟是谁在丢人，丢谁的人。&lt;br /&gt;&lt;br /&gt;我 们知道，googleearthcommunity是GE里面一个开放编辑的图层，任何人都有权限进行任何标注，从网易的报道来看，显然，记者对这种编辑 方式是颇有微词的：“想标啥就标啥，没人监管”“自由标注，没有限制”“日本人还在不断标准沈阳地图”“Google事先未审核”。言下之意，这种开放编 辑是不负责任的，GE的运行方没有能够有效的限制使用者的编辑，没有尽到事先审查的责任，所以这次沈阳标注日文地名事件，应该由捣乱的日本网友和未尽审查 义务的google共同承担责任。&lt;br /&gt;&lt;br /&gt;毫无疑问，网易的这位编辑仍然生活在我贴你看的门户网站时代，他并不能理解，开放式编辑的网站不过是网民表演的一个舞台，是闹剧，悲剧还是喜剧，抑或是荒诞剧，这一切完全取决于网民个人。&lt;br /&gt;&lt;br /&gt;在&lt;a href="https://secure.wikimedia.org/wikipedia/zh/wiki" target="_blank"&gt;维基百科&lt;/a&gt;里， 我们见过太多乐于自取其辱的白痴了，曾经有一个天文学爱好者，他不能忍受其他任何人修改他撰写的内容，在与其他网友以及管理员发生多次冲突之后，此人启动 了自编的机器人程序，对维基百科发动了灌水式攻击，我们知道了，这是一个极端自负自私的人；另有一个网友，剽窃了他人拍摄的照片，放在自己的用户页，并且 留言“谁删我跟谁急”，于是我们知道了，这是一个漠视著作权的人；还有一个网友，在与中文维基百科几乎所有的管理员都发生过争执之后，他跑去英文维基百科 告状了，他说中文维基百科的所有管理员被某党收买，死心塌地的做了某党的走狗，还好外国人没有他想象的那么愚蠢，英文的管理员直接封掉了他的帐号，于是我 们知道了，这孙子是一个卑鄙无耻的人。&lt;br /&gt;&lt;br /&gt;太多的经验告诉我们，越是开放编辑的网站，越不怕无聊无知无耻的小白来捣乱，小白越捣乱，现得眼越大。&lt;br /&gt;&lt;br /&gt;回 到GE，我们以最坏的恶意去揣测这些为沈阳标注伪满时代地名的日本人：他们是一群不折不扣的日本右翼分子，对中国怀有最大的敌意，以这种意淫的方式来恢复 日本对中国东北的殖民统治。那么他们这么做，究竟是在丢谁的人，现谁的眼？丢人现眼的恰恰是这些没有教养的日本人自己，google earth 为全世界网民提供了一个开放的空间，人家都在好好利用这个空间，做自己该做的事，只有这伙无聊的日本人，以伤害别国人民的感情为乐，把自己那见不得人的意 淫展示在全天下网民的面前。试想全世界的网民看到这伙日本人的表演之后，真的会以为，今日的沈阳就是当年的奉天吗？绝对不会，每一个正直的人，都会由衷地 鄙视这些捣乱的日本小白，他们充分地表演，侮辱的是只是他们自己，丢他们自己的人，现日本人的眼！既然他们愿意在大庭广众之下裸身卖弄，我们又着什么急 呢？让他们充分表演去吧&lt;br /&gt;&lt;br /&gt;可是我们的愤青们的表现，实在太令人失望了，在&lt;a href="http://bbs.bullog.cn/forums/main/4052.aspx" target="_blank"&gt;牛博&lt;/a&gt;有个傻逼说：&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Re: Google Earth竟用伪满洲国地图？——傻逼FQ又有攻击&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;囸 @ 2007-1-31 14:28:06 引用&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;keyhole不过是个社区。&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;而且自定义共享地标是个非默认图层。。&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;和google有JB关系啊！！！&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;不服气你们也去改日本的地标啊。。。我就把日本的靖国神厕标注为厕所。。也显示的啊。。人家日本就没有要求google什么的道歉&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;怎么对自己民族那么不自信。。。也太脆弱了吧。。。坚强点&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;乖乖，您还是歇歇吧，比那帮小日本儿还丢人！&lt;br /&gt;&lt;br /&gt;转载自 &lt;a href="http://snowyowls.blogbus.com/logs/4420487.html"&gt;相空间&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/294379627880145984-1685829454918183342?l=netfishx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://netfishx.blogspot.com/feeds/1685829454918183342/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=294379627880145984&amp;postID=1685829454918183342' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/294379627880145984/posts/default/1685829454918183342'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/294379627880145984/posts/default/1685829454918183342'/><link rel='alternate' type='text/html' href='http://netfishx.blogspot.com/2007/02/blog-post.html' title='丢谁的人'/><author><name>netfishx</name><uri>http://www.blogger.com/profile/15593804318935689524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-294379627880145984.post-5338803696919038941</id><published>2007-01-19T11:04:00.000+08:00</published><updated>2007-01-19T11:09:58.053+08:00</updated><title type='text'>rails1.2正式发布</title><content type='html'>rails1.2正式发布了，restful、更好的utf8支持，一定要抽时间好好研究一下了。争取找时间做点东西出来玩玩。&lt;br /&gt;&lt;br /&gt;官方发布消息：&lt;a href="http://weblog.rubyonrails.org/2007/1/19/rails-1-2-rest-admiration-http-lovefest-and-utf-8-celebrations"&gt;这里&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/294379627880145984-5338803696919038941?l=netfishx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://netfishx.blogspot.com/feeds/5338803696919038941/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=294379627880145984&amp;postID=5338803696919038941' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/294379627880145984/posts/default/5338803696919038941'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/294379627880145984/posts/default/5338803696919038941'/><link rel='alternate' type='text/html' href='http://netfishx.blogspot.com/2007/01/rails12.html' title='rails1.2正式发布'/><author><name>netfishx</name><uri>http://www.blogger.com/profile/15593804318935689524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-294379627880145984.post-7085716626909251467</id><published>2007-01-19T09:52:00.000+08:00</published><updated>2007-01-19T10:10:29.595+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><title type='text'>prototype1.5.0正式发布</title><content type='html'>&lt;p&gt;请注意，这才是真正的正式发布。官方网站也搬家了：&lt;a href="http://www.prototypejs.org/" target="blank"&gt;http://www.prototypejs.org&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;看ajaxian上很多人都评价说"Too little too late",这段时间prototype丢了很多人气啊。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/294379627880145984-7085716626909251467?l=netfishx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://netfishx.blogspot.com/feeds/7085716626909251467/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=294379627880145984&amp;postID=7085716626909251467' title='1 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/294379627880145984/posts/default/7085716626909251467'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/294379627880145984/posts/default/7085716626909251467'/><link rel='alternate' type='text/html' href='http://netfishx.blogspot.com/2007/01/prototype150.html' title='prototype1.5.0正式发布'/><author><name>netfishx</name><uri>http://www.blogger.com/profile/15593804318935689524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-294379627880145984.post-6736763895196408848</id><published>2007-01-17T16:23:00.000+08:00</published><updated>2007-01-17T16:40:03.893+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><title type='text'>domQuery VS. jQuery VS. prototype</title><content type='html'>由于jQuery1.1的发布，我才注意到jQuery和yui-ext/domQuery的作者针对 它们提供的dom选择器的性能爆发了一场论战。具体情况看他们的blog：&lt;a href="http://www.jackslocum.com/blog/"&gt;这里&lt;/a&gt;和&lt;a href="http://jquery.com/blog"&gt;这里&lt;/a&gt;&lt;br /&gt;他们的dom选择器功能都很全面，提供基于css selector和部分xsl的选择器。由于看不起prototype这部分功能的不完善（可怜啊），根本没有把它加入测试。所以我干脆自己测了一下，直接说结果：&lt;br /&gt;性能排列 domQuery0.40&gt;jQuery1.1&gt;prototype1.5.0RC2&gt;jQuery1.04&lt;br /&gt;domQuery的性能确实很好，在很多测试项上速度确实达到了新版jQuery的3倍甚至更多。jQuery的新版本也确实在很多项目上速度比老版本提高了数倍。让我觉得不可思议的是prototype，性能比老版本的jQuery也仅是高一点点而已。&lt;br /&gt;&lt;br /&gt;结论：prototype的$$功能不全、性能不佳，要慎用。如需复杂的dom查询，domQuery（性能极好，文档也不错）与jQuery1.1（文档极好，性能也可以接受）都是很好的选择。&lt;br /&gt;&lt;br /&gt;这里是&lt;a href="http://www.yui-ext.com/playpen/selectors/jquery/index.html"&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;测试页面&lt;/span&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/294379627880145984-6736763895196408848?l=netfishx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://netfishx.blogspot.com/feeds/6736763895196408848/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=294379627880145984&amp;postID=6736763895196408848' title='1 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/294379627880145984/posts/default/6736763895196408848'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/294379627880145984/posts/default/6736763895196408848'/><link rel='alternate' type='text/html' href='http://netfishx.blogspot.com/2007/01/domquery-vs-jquery-vs-prototype.html' title='domQuery VS. jQuery VS. prototype'/><author><name>netfishx</name><uri>http://www.blogger.com/profile/15593804318935689524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-294379627880145984.post-4667147147883687548</id><published>2007-01-17T09:15:00.000+08:00</published><updated>2007-01-17T09:30:14.108+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='其他技术'/><title type='text'>用greasemonkey搞定google快照</title><content type='html'>曾经为了快照选百度而弃谷歌，不过自从发现了这个办法，我又重回谷歌怀抱了。&lt;br /&gt;第一步，请确定你用的是firefox浏览器。&lt;br /&gt;第二步，安装&lt;a href="http://addons.mozine.cn/firefox/16/"&gt;greasemonkey&lt;/a&gt;插件（非常有用的插件，具体情况看&lt;a href="http://addons.mozine.cn/firefox/16/"&gt;介绍&lt;/a&gt;）。&lt;br /&gt;第三步，安装这段&lt;a href="http://community.mozine.cn/index.php?act=attach&amp;type=post&amp;amp;id=5739"&gt;用户脚本&lt;/a&gt;。&lt;br /&gt;重启，大功告成。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/294379627880145984-4667147147883687548?l=netfishx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://netfishx.blogspot.com/feeds/4667147147883687548/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=294379627880145984&amp;postID=4667147147883687548' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/294379627880145984/posts/default/4667147147883687548'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/294379627880145984/posts/default/4667147147883687548'/><link rel='alternate' type='text/html' href='http://netfishx.blogspot.com/2007/01/greasemonkeygoogle.html' title='用greasemonkey搞定google快照'/><author><name>netfishx</name><uri>http://www.blogger.com/profile/15593804318935689524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-294379627880145984.post-1965070590660124025</id><published>2007-01-16T13:37:00.000+08:00</published><updated>2007-01-16T14:16:07.668+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><title type='text'>jQuery1.1发布</title><content type='html'>&lt;p&gt;jQuery1.1发布了，本来我是很不喜欢这套js framework的，原因还是那两点：性能和态度（整天跟prototype比大小，却不用同样的标准）。不过这次的新版本看来在这两点上改变了很多，可以抽时间来研究一下了，毕竟它的易用性确实很好。&lt;/p&gt;&lt;br /&gt;官方发布页：&lt;a href="http://jquery.com/blog/2007/01/14/jquery-birthday-11-new-site-new-docs/"&gt;http://jquery.com/blog/2007/01/14/jquery-birthday-11-new-site-new-docs/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/294379627880145984-1965070590660124025?l=netfishx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://netfishx.blogspot.com/feeds/1965070590660124025/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=294379627880145984&amp;postID=1965070590660124025' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/294379627880145984/posts/default/1965070590660124025'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/294379627880145984/posts/default/1965070590660124025'/><link rel='alternate' type='text/html' href='http://netfishx.blogspot.com/2007/01/jquery11.html' title='jQuery1.1发布'/><author><name>netfishx</name><uri>http://www.blogger.com/profile/15593804318935689524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-294379627880145984.post-5505740601856915908</id><published>2007-01-15T13:52:00.000+08:00</published><updated>2007-01-15T14:30:13.293+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><title type='text'>“取消”和“停止”浏览器事件</title><content type='html'>&lt;p&gt;这种做法是从Bret Taylor的blog上面抄来的，原文地址在&lt;a href="http://ajaxcookbook.org/canceling-and-stopping-browser-events/"&gt;这里&lt;/a&gt;（好像是，不是也别怪我。）。对于避免ajax应用中不同层的事件干扰很有用的。&lt;/p&gt;&lt;br /&gt;&lt;p&gt;先说一下“取消(cancel)”和“停止(stop)”的区别:说白了，停止就是当事件发生后，阻止它自动冒泡到父容器内；而取消则是当冒泡发生到父容器之后停止，也就是不在当前元素中响应。天哪，这东西说起来话长了，代码说话：&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;function stopEvent(e) {&lt;br /&gt;    if (!e) e = window.event;&lt;br /&gt;    if (e.stopPropagation) {&lt;br /&gt;        e.stopPropagation();&lt;br /&gt;    } else {&lt;br /&gt;        e.cancelBubble = true;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;var link = document.getElementById("link");&lt;br /&gt;link.onclick = stopEvent;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;以上这一段是阻止父容器事件的&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;function cancelEvent(e) {&lt;br /&gt;    if (!e) e = window.event;&lt;br /&gt;    if (e.preventDefault) {&lt;br /&gt;        e.preventDefault();&lt;br /&gt;    } else {&lt;br /&gt;        e.returnValue = false;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;var link = document.getElementById("link");&lt;br /&gt;link.onclick = function(e) {&lt;br /&gt;    cancelEvent(e);&lt;br /&gt;    stopEvent(e);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;以上这一段是阻止子元素事件的&lt;/p&gt;&lt;br /&gt;&lt;p&gt;例子地址在这里：&lt;a href="http://ajaxcookbook.org/examples/stopevent.html"&gt;demo&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/294379627880145984-5505740601856915908?l=netfishx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://netfishx.blogspot.com/feeds/5505740601856915908/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=294379627880145984&amp;postID=5505740601856915908' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/294379627880145984/posts/default/5505740601856915908'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/294379627880145984/posts/default/5505740601856915908'/><link rel='alternate' type='text/html' href='http://netfishx.blogspot.com/2007/01/blog-post_15.html' title='“取消”和“停止”浏览器事件'/><author><name>netfishx</name><uri>http://www.blogger.com/profile/15593804318935689524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-294379627880145984.post-1193785693640682279</id><published>2007-01-14T21:05:00.000+08:00</published><updated>2007-01-14T23:33:34.888+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='web2.0'/><title type='text'>月光博客也出事了？？？</title><content type='html'>&lt;p&gt;起因是下午用&lt;a href="http://reader.google.com"&gt;google reader&lt;/a&gt;的时候，突然不能访问了，google的所有服务也几乎都无法访问。百度一下才知道，很可能是由于&lt;a href="http://reader.google.com"&gt;google reader&lt;/a&gt;中订阅的某个feed的原因。&lt;span style="text-decoration:line-through"&gt;顺藤摸瓜找下去，发现&lt;a href="http://www.williamlong.info"&gt;月光博客&lt;/a&gt;已无法访问，联想最近的某些事情，恐怕某些不愿看到的事情发生了。&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;年前果然是多事之秋啊。。。。。。&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;更新：猜错了，原因未知。用https可以访问&lt;a href="http://reader.google.com"&gt;google reader&lt;/a&gt;。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/294379627880145984-1193785693640682279?l=netfishx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://netfishx.blogspot.com/feeds/1193785693640682279/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=294379627880145984&amp;postID=1193785693640682279' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/294379627880145984/posts/default/1193785693640682279'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/294379627880145984/posts/default/1193785693640682279'/><link rel='alternate' type='text/html' href='http://netfishx.blogspot.com/2007/01/blog-post_14.html' title='月光博客也出事了？？？'/><author><name>netfishx</name><uri>http://www.blogger.com/profile/15593804318935689524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-294379627880145984.post-6600130899833222950</id><published>2007-01-14T18:11:00.000+08:00</published><updated>2007-01-14T18:41:02.342+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='web2.0'/><title type='text'>越来越喜欢google</title><content type='html'>&lt;p&gt;这么久以来我写blog都是断断续续的，主要原因是自己太懒，不过一直找不到一个好的&lt;abbr title="blog service provider"&gt;BSP&lt;/abbr&gt;也是一个重要原因。这次我直到blogspot解封之后把blog搬到这里才发现（懒，动作实在很慢），一个好的&lt;abbr title="blog service provider"&gt;BSP&lt;/abbr&gt;对blogger的促进是不可言喻的。新版&lt;a href="http://www.blogger.com"&gt;Blogger&lt;/a&gt;更好用了,我尤其喜欢它提供给用户充分的自主权，国内的&lt;abbr title="blog service provider"&gt;BSP&lt;/abbr&gt;相比之下就。。。。。。&lt;/p&gt;&lt;br /&gt;&lt;p&gt;说回主题，为什么说我越来越喜欢&lt;a href="http://www.google.com"&gt;google&lt;/a&gt;呢？除了换了&lt;abbr title="blog service provider"&gt;BSP&lt;/abbr&gt;，我这次还换了rss订阅的服务，从&lt;a href="http://www.zhuaxia.com"&gt;抓虾&lt;/a&gt;换到&lt;a href="http://www.google.com/reader/"&gt;google reader&lt;/a&gt;了。线上的 RSS 阅读器我最初用的是&lt;a href="http://www.bloglines.com"&gt;bloglines&lt;/a&gt;,可惜身处伟大的&lt;abbr title="......"&gt;GFW&lt;/abbr&gt;之后，再加上网络条件的问题，所以刚知道&lt;a href="http://www.zhuaxia.com"&gt;抓虾&lt;/a&gt;就马上搬过去了。期间也曾经考虑过&lt;a href="http://www.google.com/reader/"&gt;google reader&lt;/a&gt;，可惜那时的&lt;a href="http://www.google.com/reader/"&gt;google reader&lt;/a&gt;不愧为最差劲的google产品。不过最近&lt;a href="http://www.zhuaxia.com"&gt;抓虾&lt;/a&gt;开始不断抽风，重新跑回&lt;a href="http://www.google.com/reader/"&gt;google reader&lt;/a&gt;一看：天哪，这不就是我想要的吗？漂亮的聚合式浏览，完美的Start 和 Tag，再加上阅读趋势、批量订阅处理和酷酷的滚动事件触发（这个要研究一下，ajax应用是我最关心的）。二话不说，俺搬家了。&lt;/p&gt;&lt;br /&gt;&lt;p&gt;说了这么多，其实&lt;a href="http://www.google.com/reader/"&gt;google reader&lt;/a&gt;还是有些缺点的：中文tag的支持好像还没有（应该不是大问题，相信很快会加上的），速度（这个就没话说了，谁让咱生在这个伟大的国度呢？忍了吧。）。&lt;/p&gt;&lt;br /&gt;&lt;p&gt;顺便再说一句，针对firefox3.0的&lt;a href="http://toolbar.google.com"&gt;google toolbar&lt;/a&gt;好像也可以用了。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/294379627880145984-6600130899833222950?l=netfishx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://netfishx.blogspot.com/feeds/6600130899833222950/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=294379627880145984&amp;postID=6600130899833222950' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/294379627880145984/posts/default/6600130899833222950'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/294379627880145984/posts/default/6600130899833222950'/><link rel='alternate' type='text/html' href='http://netfishx.blogspot.com/2007/01/google.html' title='越来越喜欢google'/><author><name>netfishx</name><uri>http://www.blogger.com/profile/15593804318935689524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-294379627880145984.post-2162735069016427619</id><published>2007-01-13T21:35:00.000+08:00</published><updated>2007-01-14T09:13:48.591+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='其他技术'/><title type='text'>wordpress实在是很有意思</title><content type='html'>&lt;p&gt;wordpress是一个php的blog程序，支持插件方式扩展，功能相当完善，比起java世界中那些无比复杂的blog程序不知道好多少倍。&lt;/p&gt;&lt;p&gt;很早就听说了这东西，不过由于不懂php一直也没有去碰,直到昨天。昨天为了找个好点的bsp重写blog折腾了一晚上，今天一怒之下直接自己装WP开始玩。果然一玩就上瘾了，模版、插件，好玩的东西真不少。今天已经写了一个模版出来，我的xhtml/css/js终于有用武之地了，再不用像在公司还要顾虑那么多。&lt;/p&gt;&lt;p&gt;爽！&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/294379627880145984-2162735069016427619?l=netfishx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://netfishx.blogspot.com/feeds/2162735069016427619/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=294379627880145984&amp;postID=2162735069016427619' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/294379627880145984/posts/default/2162735069016427619'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/294379627880145984/posts/default/2162735069016427619'/><link rel='alternate' type='text/html' href='http://netfishx.blogspot.com/2007/01/wordpress.html' title='wordpress实在是很有意思'/><author><name>netfishx</name><uri>http://www.blogger.com/profile/15593804318935689524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-294379627880145984.post-7473056037284098683</id><published>2007-01-13T15:00:00.000+08:00</published><updated>2007-01-13T20:53:06.322+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='生活'/><title type='text'>蝙蝠侠无所不能</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_8Ei3PrasL5o/RaiJMQJloTI/AAAAAAAAAAc/3m7dmDGZ5js/s320/2.jpg" alt="" id="BLOGGER_PHOTO_ID_5019412628291035442" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" &gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_8Ei3PrasL5o/RaiI7QJloSI/AAAAAAAAAAU/WBWk3uOku30/s320/1.jpg" alt="" id="BLOGGER_PHOTO_ID_5019412336233259298" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;相信如今的人们再也不会怀疑火箭年初的这笔交易了。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/294379627880145984-7473056037284098683?l=netfishx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://netfishx.blogspot.com/feeds/7473056037284098683/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=294379627880145984&amp;postID=7473056037284098683' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/294379627880145984/posts/default/7473056037284098683'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/294379627880145984/posts/default/7473056037284098683'/><link rel='alternate' type='text/html' href='http://netfishx.blogspot.com/2007/01/blog-post.html' title='蝙蝠侠无所不能'/><author><name>netfishx</name><uri>http://www.blogger.com/profile/15593804318935689524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_8Ei3PrasL5o/RaiJMQJloTI/AAAAAAAAAAc/3m7dmDGZ5js/s72-c/2.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-294379627880145984.post-1431214569679153071</id><published>2007-01-12T23:30:00.000+08:00</published><updated>2007-01-12T23:50:51.147+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ide'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><title type='text'>好消息，textmate的windows版本Intype快要出来了</title><content type='html'>&lt;p&gt;以下转自cnbeta.com&lt;br /&gt;&lt;/p&gt;&lt;div class="quote_title"&gt;引用&lt;/div&gt;Intype alpha 0.2.x 提供下载  &lt;p&gt;软件新闻leonardo投递:&lt;br /&gt;有些人可能没有听过这个名字,不过说起他的兄弟 TextMate 或许有 Apple 经验的人就不陌生了吧.这个 Intype 就是他的 Windows 版本的实现.以下为邮件原文:&lt;/p&gt;  &lt;p&gt;Hello,&lt;br /&gt;we are proud to announce our first Intype Alpha release.&lt;/p&gt;  &lt;p&gt;Download link is available at:&lt;br /&gt;&lt;a href="http://intype.info/home/" target="blank"&gt;http://intype.info/home/&lt;/a&gt;  &lt;/p&gt;&lt;p&gt;Support forums are available at:&lt;br /&gt;&lt;a href="http://intype.info/forums/" target="blank"&gt;http://intype.info/forums/&lt;/a&gt;  &lt;/p&gt;&lt;p&gt;Your e-mail address has been deleted from our database and&lt;br /&gt;no further e-mails will be sent to you.&lt;/p&gt;  &lt;p&gt;Next releases will be announced via Intype Blog and&lt;br /&gt;Intype Forums.&lt;/p&gt;  Thank you for your interest,&lt;br /&gt;Intype Team&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/294379627880145984-1431214569679153071?l=netfishx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://netfishx.blogspot.com/feeds/1431214569679153071/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=294379627880145984&amp;postID=1431214569679153071' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/294379627880145984/posts/default/1431214569679153071'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/294379627880145984/posts/default/1431214569679153071'/><link rel='alternate' type='text/html' href='http://netfishx.blogspot.com/2007/01/textmatewindowsintype.html' title='好消息，textmate的windows版本Intype快要出来了'/><author><name>netfishx</name><uri>http://www.blogger.com/profile/15593804318935689524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-294379627880145984.post-1787557926395209305</id><published>2007-01-12T23:28:00.000+08:00</published><updated>2007-01-12T23:49:45.005+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='转贴'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>(转贴)架构css</title><content type='html'>跟上一篇是同一位作者，翻译的这两篇文章真不错啊。正好google又见鬼的不能访问了，直接促使我下定决心重开blog。废话不说了。&lt;br /&gt;&lt;br /&gt;&lt;p&gt;大约一个月之前，看到了&lt;a href="http://www.garrettdimon.com/"&gt;Garrett Dimon&lt;/a&gt;的这篇&lt;a href="http://www.digital-web.com/articles/architecting_css/"&gt;《Architecting CSS》&lt;/a&gt;，不禁动了翻过来的念头。联系作者后他满口答应，我也准备3天之内完工。只可惜国庆假期琐事繁多，一直腾不出手来开工。拖啊拖拖啊拖，一直到今天才得完成。这效率……唉，真是愧对作者，希望他别见怪~&lt;/p&gt; &lt;p&gt;废话不说了，回到主题。关于这篇文章，我有两个声明：1.&lt;strong&gt;不是css用法指南&lt;/strong&gt;，而是宏观上的组织架构方法；2.&lt;strong&gt;没有提出绝对正确的某种方案&lt;/strong&gt;，而是列出多种方案以及利弊让你根据具体情况选择。&lt;/p&gt; &lt;p&gt;全文如下：&lt;/p&gt; &lt;h2&gt;架构css&lt;/h2&gt; &lt;p&gt;作者：Garrett Dimon&lt;br /&gt;翻译：htmlor&lt;/p&gt; &lt;p&gt;在当前浏览器普遍支持的前提下，css被我们赋予了前所未有的使命。然而依赖css越多，样式表文件就会变得越大越复杂。与此同时，文件维护和组织的考验也随之而来。&lt;/p&gt; &lt;p&gt;（曾几何时）只要一个css文件就够了——所有规则（rule）汇聚一堂，增删改都很方便——可这种日子早已远去。（现在）建立新网站时，必须花点时间好好筹划怎么组织和架构css。&lt;/p&gt; &lt;h3&gt;文件的组织&lt;/h3&gt; &lt;p&gt;构建css系统的第一步是大纲的拟定。（我认为）css组织规划的重要性堪比网站目录结构。（htmlor注：用词夸张一点，让你加深记忆） 没有哪种方案放之四海而皆准，因此我们会讨论一些基本的组织方案，以及它们各自的利弊。&lt;/p&gt; &lt;h4&gt;主css文件&lt;/h4&gt; &lt;p&gt;通常可以使用一个主css文件，来放置所有页面共享的规则。这个文件会包含默认的字体、链接、页眉和其他等样式。有了主css文件之后，我们开始探讨高级组织策略。&lt;/p&gt; &lt;h4&gt;方法一：基于原型&lt;/h4&gt; &lt;p&gt;最基本的策略是基于原型页面（archetype page）分离css文件。假如一个网站的首页、子页面和组合页设计不同，就可以采用基于原型的策略。（这种策略下）每个页面都会有专属的css文件。&lt;/p&gt; &lt;p&gt;在原型数量不多的情况下，这个方法简单明了、行之有效。然而，当页面元素并不按部就班的位于各个原型页时，问题就出现了。如果子页面和组合页共享某些元素，而首页却没有，我们应该怎么做呢？&lt;/p&gt; &lt;ol&gt;&lt;li&gt;&lt;strong&gt;把共享元素放入主css文件。&lt;/strong&gt;这虽不是最纯正的解决办法，却适用于某些具体情况。可是如果网站庞大，（这样做的话）主css文件会迅速膨胀——这就违背了分离文件的初衷：避免导入不必要的大文件。&lt;/li&gt;&lt;li&gt;&lt;strong&gt;在组合页和子页面的css文件里各放一份样式代码。&lt;/strong&gt;（这么做）就意味着要维护冗余代码，很显然我们不想这样。&lt;/li&gt;&lt;li&gt;&lt;strong&gt;创建一个新的文件，由这两种页面共享。&lt;/strong&gt;这听起来不错。不过假如只有10行代码，我们创建这个文件仅仅是为了共享这10行代码？（htmlor注：杀鸡用牛刀？） 这方法很纯粹，但如果网站庞大有很多对页面共享很少量元素时（htmlor注：比如30对页面分别共享10行代码），就显得很笨重了。&lt;/li&gt;&lt;li&gt;&lt;strong&gt;创建一个单独的css文件，包含所有共享元素的样式。&lt;/strong&gt;这方法可能比较简单，却要取决于网站的大小和共享元素的多少。有种情况会很烦：导入了一个很大的css文件，但页面只用到一小部分样式——还是那句话，这违背了分离文件的初衷。&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;这就是我所说的&lt;strong&gt;重叠的两难&lt;/strong&gt;（overlap dilemma）。零碎css规则的重叠不一而足，并没有一个完全清晰无误的方案来组织它们。&lt;/p&gt; &lt;h4&gt;方法二：基于页面元素/块&lt;/h4&gt; &lt;p&gt;如果网站使用服务器端include，这个方法会很不错。举例说明，如果使用页眉include，它会有自己相应的css文件。页脚或者其他部分的include可以如法炮制，只须导入自己的css文件。这个方法简单干净，不过可能会产生很多小css文件。&lt;/p&gt; &lt;p&gt;举例来说，假如页脚的样式只需要20行css代码，单独创建一个文件就划不来了。而且这个方法会导致每个页面都包含一堆css文件——因为有多少include，就得有多少css文件。&lt;/p&gt; &lt;h4&gt;方法三：基于标记&lt;/h4&gt; &lt;p&gt;这个方案直观实际，与前一个类似。如果网站共有30个页面，其中10个含有form，那么可以创建一个css文件专门处理form的样式，只在这10个页面导入它。如果另外10个页面含有table，就创建一个文件专门处理table样式……诸如此类。&lt;/p&gt; &lt;h4&gt;另外的组织技巧&lt;/h4&gt; &lt;p&gt;除了用主观的方法组织文件，我们还要考虑如打印、手持设备和屏幕等多种媒体类型。这虽然已经很清楚的定义过，可依旧是建立文件结构时应该考虑的一个因素。一旦必须支持多种媒体类型，主css文件里的某些规则可能就得重新考虑。&lt;/p&gt; &lt;p&gt;另外，品牌联合也可能是一个重要因素。（htmlor注：如&lt;a href="http://www.google.com/"&gt;google&lt;/a&gt;和&lt;a href="http://www.nike.com/"&gt;nike&lt;/a&gt;联手推出的&lt;a href="http://www.joga.com/"&gt;joga&lt;/a&gt;） 如果涉及品牌联合，你就得考虑哪些元素应该调整以适应另一品牌。比如分别使用不同的css文件等。&lt;/p&gt; &lt;p&gt;还有一个常被忽略的技巧：使用嵌套的&lt;code&gt;@import&lt;/code&gt;语句。只包含一连串&lt;code&gt;@import&lt;/code&gt;语句，或者再加几句css规则，就能创建一个css文件。用这个方法完全可以创建网站的主css文件（用&lt;code&gt;@import&lt;/code&gt;导入各部分的样式文件）。假如网站的每个页面都导入了4到5个不同的css文件，无疑你应该考虑使用这个技巧。&lt;/p&gt; &lt;h3&gt;规则和选择器的组织&lt;/h3&gt; &lt;p&gt;谈完了文件组织，接着讨论一下怎么组织文件里的东西吧。很自然，我们希望在文件里畅通无阻的浏览，迅速找到要编辑的选择器（selector）或规则。&lt;/p&gt; &lt;h4&gt;冗余 vs. 附属&lt;/h4&gt; &lt;p&gt;正如Dave Shea在其文章&lt;a href="http://www.mezzoblue.com/archives/2005/01/20/redundancy_v/"&gt;《冗余 vs. 附属》&lt;/a&gt;（Redundancy vs. Dependency）里所说的，你必须不断了解级联（cascade）。你要决定是对选择器编组（意味着附属），还是把它们分离（意味着冗余）。编组可 以保持代码简洁扼要，可是会建立附属关系，导致维护开销增加。如果不编组，就会增加文件大小，让相似的选择器保持一致变得困难。只有做好这种权衡、取舍， 才能每次都作出正确的决定。&lt;/p&gt; &lt;h4&gt;按相互关系/上下文编组&lt;/h4&gt; &lt;p&gt;既然文件组织可以是主观的，那么显然，按照规则和选择器与其他部分的相互关系来进行编组是最好的方法。举例说明，假设你用容器、页眉和页脚来完成布局，就应该把它们编成一组。&lt;/p&gt; &lt;p&gt;这似乎很简单，其实不然。比如，把页眉中的导航加入css时，是将它跟父元素编组还是独立编组？这种情况下，要视乎规则的上下文。通常，页眉与页面布局相关，应该与其他布局元素一起编组。而导航是页眉的一块，应该和页眉的其他块编组，而不是页眉本身。&lt;/p&gt; &lt;h4&gt;使用注释&lt;/h4&gt; &lt;p&gt;跟大多数代码类似，注释是组织良好与否的关键。应该根据css的控制范围，清楚的标注每节（section）。最好确保注释视觉突出，以便在内容滚动、一目十行时快速定位。&lt;/p&gt; &lt;p&gt;Doug Bowman在其文章&lt;a href="http://www.stopdesign.com/log/2005/05/03/css-tip-flags.html"&gt;《css组织技巧之一：标记》&lt;/a&gt;（CSS Organization Tip #1: Flags）里把css注释玩得高明之极。他详细说明了在节名之前加上等号，以便使用文本编辑器的查找功能迅速跳到某节。&lt;/p&gt; &lt;h4&gt;别忘了&lt;/h4&gt; &lt;p&gt;你应该细致认真的了解了&lt;a href="http://www.w3.org/TR/CSS21/cascade.html"&gt;特异性、级联和继承&lt;/a&gt;，并善用它们。它们之中的每一项都可以是你最可怕的敌人，也可以是你最友善的朋友。当建立庞大的网站时，是否理解这些细微精妙之处，决定了你所构建的是坚如磐石的系统，还是经不起风雨的豆腐渣工程。（htmlor注：这句完全意译，比较爽）&lt;/p&gt; &lt;h3&gt;属性的组织&lt;/h3&gt; &lt;p&gt;现在我们了解了文件的组织，也知道了文件内规则的组织，但还有一个重要的组织环节（没有提到），那就是属性（attribute）。虽然属性比前两个概念更简单，可是还有一些非常好的、能够保持规则整洁的方法很值得一提。&lt;/p&gt; &lt;h4&gt;按字母排序&lt;/h4&gt; &lt;p&gt;提到属性，如果说需要遵循什么原则的话，那就是：按-字-母-排-序。其实这招对于属性浏览帮助不大，不过可以防止属性值覆盖这种偶然事件的发生。&lt;/p&gt; &lt;p&gt;举个例子吧，已经数不清有多少次，我为某个选择器定义过了&lt;code&gt;margin&lt;/code&gt;值，之后的某天无意间又加了一个（或前或后）。（这种情况下）后一个属性自然会起作用。假设不知道第二个属性存在，不管我怎么调整第一个属性值、刷新浏览器，也看不到页面变化。（htmlor注：这个问题我深有体会） 如果按照字母顺序排列，你就会发现&lt;code&gt;margin&lt;/code&gt;被定义了两次（因为它们挨在一起），这个问题自然可以避免。&lt;/p&gt; &lt;h4&gt;优先项&lt;/h4&gt; &lt;p&gt;当网站复杂、牵涉太多css文件时，会建立大量的附属关系。一旦需要定制某个元素特有的样式，&lt;code&gt;!important&lt;/code&gt;选项似乎是最佳选择。没错，&lt;code&gt;!important&lt;/code&gt;是能解一时之需，但最好搞清楚导致问题的根源，然后根据级联关系决定是否真的需要用它。&lt;/p&gt; &lt;p&gt;如果你对上文提到的特异性、级联和继承很熟悉，大可不必抱着&lt;code&gt;!important&lt;/code&gt;一颗树不放。（htmlor注：整片森林等着你~） 当然它还是会派上用场，不过使用之前要对具体情况了然于胸。千万不要因为不知问题的症结所在而把&lt;code&gt;!important&lt;/code&gt;当作捷径或是补救方案。&lt;/p&gt; &lt;h3&gt;小结&lt;/h3&gt; &lt;p&gt;当我们变得依赖css而使样式表日渐复杂时，就需要正确的计划来避免犯错，并使代码易于维护。既然完美无缺的方案并不存在，那么了解css的工作方式以及文件、选择器和属性的多种组织方案，无疑有助于我们写出优质的代码，经受住时间考验。&lt;/p&gt; &lt;p&gt;（完）&lt;br /&gt;&lt;/p&gt; 原文链接 ： http://blog.htmlor.com/2006/10/31/architecting_css/&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/294379627880145984-1787557926395209305?l=netfishx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://netfishx.blogspot.com/feeds/1787557926395209305/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=294379627880145984&amp;postID=1787557926395209305' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/294379627880145984/posts/default/1787557926395209305'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/294379627880145984/posts/default/1787557926395209305'/><link rel='alternate' type='text/html' href='http://netfishx.blogspot.com/2007/01/css.html' title='(转贴)架构css'/><author><name>netfishx</name><uri>http://www.blogger.com/profile/15593804318935689524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-294379627880145984.post-4607370990288810744</id><published>2007-01-12T22:55:00.000+08:00</published><updated>2007-01-12T23:51:58.250+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='转贴'/><title type='text'>（转贴）flickr对javascript干的好事</title><content type='html'>&lt;p&gt;在一个讨论web技术的网站&lt;a href="http://www.thinkvitamin.com/"&gt;vitamin&lt;/a&gt;上发现这篇&lt;a href="http://www.thinkvitamin.com/features/webapps/serving-javascript-fast"&gt;《Serving JavaScript Fast》&lt;/a&gt;，读过之后大有收获，茅塞顿开。于是就有了翻译过来的念头——我这人有个毛病，看到有意思的英文文章，就想自己翻过来（虽然英文水平很烂）。先在网上查了查，已经有blog谈到这篇文章（我算是后知后觉了），有总结要点的&lt;a href="http://www.dbanotes.net/web/flickr_web_tech.html"&gt;《Flickr 的开发者的 Web 应用优化技巧》&lt;/a&gt;，也有延伸开来的&lt;a href="http://blog.94smart.com/2006/05/26/744.html"&gt;《接着讲Flickr的八卦》&lt;/a&gt;，但似乎没有全文翻译的（这下就好，不会忙了半天发现是无用功）。之后，就写信问作者可不可以，作者一口答应：“sure - i’d love you to translate it”，只是要求我翻好之后给他一个链接地址。得到准许，心里就有底了。&lt;/p&gt; &lt;p&gt;先介绍一下作者。&lt;a href="http://www.iamcal.com/"&gt;Cal Henderson&lt;/a&gt;，伦敦人，现居加利福尼亚的旧金山。PHP，MySQL和Perl专家，现任&lt;a href="http://www.flickr.com/"&gt;flickr&lt;/a&gt;架构师（flickr被收购后就在&lt;a href="http://www.yahoo.com/"&gt;yahoo&lt;/a&gt;了），同时也是vitamin的&lt;a href="http://www.thinkvitamin.com/advisors/cal_henderson.php"&gt;特聘顾问&lt;/a&gt;（写些技术性文章）。&lt;/p&gt; &lt;p&gt;既然他是架构师，flickr用的应该就是文中谈到的这些技术，于是参照文章，再对比网站，种种迹象表明确实如此。虽然在中国访问flickr速度 不敢恭维，加速效果不得而知，但其用了n多css和javascript资源却似乎从没出过什么问题，也从侧面印证了这些技术的有效性。&lt;/p&gt; &lt;p&gt;仔细的看完文章，还有个强烈的感觉：这老兄也太能卖关子了，一句话非分成三句说，摆事实讲道理是够透彻，就是有点太@#$%了…… 算了，他怎么说我怎么翻吧，忠实于原著嘛，要不就成篡改了。经过几天努力，加上同事&lt;a href="http://my.donews.com/thincat/"&gt;thincat&lt;/a&gt;兄倾力援手（小弟不胜感激啊），终于完工（@_@ 真是苦力活啊，我再也不想干了～）。&lt;/p&gt; &lt;p&gt;全文翻译如下：&lt;/p&gt; &lt;h2&gt;让javascript跑得更快&lt;/h2&gt; &lt;p&gt;作者：Cal Henderson&lt;/p&gt; &lt;p&gt;下一代web应用让javascript和css得堪大用。我们会告诉你怎样使这些应用又快又灵。&lt;/p&gt; &lt;p&gt;建立了号称“Web 2.0”的应用，也实现了富内容（rich content）和交互，我们期待着css和javascript扮演更加重要的角色。为使应用干净利落，我们需要完善那些渲染页面的文件，优化其大小和 形态，以确保提供最好的用户体验——在实践中，这就意味着一种结合：使内容尽可能小、下载尽可能快，同时避免对未改动资源不必要的重新获取。&lt;/p&gt; &lt;p&gt;由于css和js文件的形态，情况有点复杂。跟图片相比，其源代码很有可能频繁改动。而一旦改动，就需要客户端重新下载，使本地缓存无效（保存在其 他缓存里的版本也是如此）。在这篇文章里，我们将着重探讨怎样使用户体验最快：包括初始页面的下载，随后页面的下载，以及随着应用渐进、内容变化而进行的 资源下载。&lt;/p&gt; &lt;p&gt;我始终坚信这一点：对开发者来说，应该尽可能让事情变得简单。所以我们青睐于那些能让系统自动处理优化难题的方法。只需少许工作量，我们就能建立一举多得的环境：它使开发变得简单，有极佳的终端性能，也不会改变现有的工作方式。&lt;/p&gt; &lt;h3&gt;好大一沱&lt;/h3&gt; &lt;p&gt;老的思路是，为优化性能，可以把多个css和js文件合并成极少数大文件。跟十个5k的js文件相比，合并成一个50k的文件更好。虽然代码总字节 数没变，却避免了多个HTTP请求造成的开销。每个请求都会在客户端和服务器两边有个建立和消除的过程，导致请求和响应header带来开销，还有服务器 端更多的进程和线程资源消耗（可能还有为压缩内容耗费的cpu时间）。&lt;/p&gt; &lt;p&gt;（除了HTTP请求，）并发问题也很重要。默认情况下，在使用持久连接（persistent connections）时，ie和firefox在同一域名内只会同时下载&lt;a href="http://blogs.msdn.com/ie/archive/2005/04/11/407189.aspx"&gt;两个资源&lt;/a&gt;（在&lt;a href="http://www.ietf.org/rfc/rfc2616.txt"&gt;HTTP 1.1规格书&lt;/a&gt;中第8.1.4节的建议）（htmlor注：可以通过修改注册表等方法改变这一默认配置）。这就意味着，在我们等待下载2个js文件的同时，将无法下载图片资源。也就是说，这段时间内用户在页面上看不到图片。&lt;/p&gt; &lt;p&gt;（虽然合并文件能解决以上两个问题，）可是，这个方法有两个缺点。第一，把所有资源一起打包，将强制用户一次下载完所有资源。如果（不这么做，而 是）把大块内容变成多个文件，下载开销就分散到了多个页面，同时缓解了会话中的速度压力（或完全避免了某些开销，这取决于用户选择的路径）。如果为了随后 页面下载得更快而让初始页面下载得很慢，我们将发现更多用户根本不会傻等着再去打开下一个页面。&lt;/p&gt; &lt;p&gt;第二（这个影响更大，一直以来却没怎么被考虑过），在一个文件改动很频繁的环境里，如果采用单文件系统，那么每次改动文件都需要客户端把所有css和js重新下载一遍。假如我们的应用有个100k的合成的js大文件，任何微小的改动都将强制客户端把这100k再消化一遍。&lt;/p&gt; &lt;h3&gt;分解之道&lt;/h3&gt; &lt;p&gt;（看来合并成大文件不太合适。）替代方案是个折中的办法：把css和js资源分散成多个子文件，按功能划分、保持文件个数尽可能少。这个方案也是有 代价的，虽说开发时代码分散成逻辑块（logical chunks）能提高效率，可在下载时为提高性能还得合并文件。不过，只要给build系统（把开发代码变成产品代码的工具集，是为部署准备的）加点东 西，就没什么问题了。&lt;/p&gt; &lt;p&gt;对于有着不同开发和产品环境的应用来说，用些简单的技术可以让代码更好管理。在开发环境下，为使条理清晰，代码可以分散为多个逻辑部分（logical components）。可以在&lt;a href="http://smarty.php.net/"&gt;Smarty&lt;/a&gt;（一种php模板语言）里建立一个简单的函数来管理javascript的下载：&lt;/p&gt; &lt;pre&gt;SMARTY:&lt;br /&gt;{insert_js files="foo.js,bar.js,baz.js"}&lt;br /&gt;&lt;br /&gt;PHP:&lt;br /&gt;function smarty_insert_js($args){&lt;br /&gt;foreach (explode(',', $args['files']) as $file){&lt;br /&gt;  echo "&amp;lt;script type='\"text' /&amp;gt;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;OUTPUT:&lt;br /&gt;&amp;lt;script type='text/javascript' source='/javascript/foo.js'&amp;lt;&amp;gt;/script&amp;gt;&lt;br /&gt;&amp;lt;script type='text/javascript' source='/javascript/bar.js'&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script type='text/javascript' source='/javascript/baz.js'&amp;gt;&amp;lt;/script&amp;gt; &lt;/pre&gt; &lt;p&gt;（htmlor注：wordpress中会把“src”替换成不知所谓的字符，因此这里只有写成“SOURCE”，使用代码时请注意替换，下同）&lt;/p&gt; &lt;p&gt;就这么简单。然后我们就命令build过程（build process）去把确定的文件合并起来。这个例子里，合并的是foo.js和bar.js，因为它们几乎总是一起下载。我们能让应用配置记住这一点，并修改模板函数去使用它。（代码如下：）&lt;/p&gt; &lt;pre&gt;SMARTY:&lt;br /&gt;{insert_js files="foo.js,bar.js,baz.js"}&lt;br /&gt;&lt;br /&gt;PHP:&lt;br /&gt;# 源文件映射图。在build过程合并文件之后用这个图找到js的源文件。&lt;br /&gt;&lt;br /&gt;$GLOBALS['config']['js_source_map'] = array(&lt;br /&gt;'foo.js' =&gt; 'foobar.js',&lt;br /&gt;'bar.js' =&gt; 'foobar.js',&lt;br /&gt;'baz.js' =&gt; 'baz.js',&lt;br /&gt;);&lt;br /&gt;&lt;br /&gt;function smarty_insert_js($args){&lt;br /&gt;if ($GLOBALS['config']['is_dev_site']){&lt;br /&gt;  $files = explode(',', $args['files']);&lt;br /&gt;}else{&lt;br /&gt;  $files = array();&lt;br /&gt;  foreach (explode(',', $args['files']) as $file){&lt;br /&gt;    $files[$GLOBALS['config']['js_source_map'][$file]]++;&lt;br /&gt;  }&lt;br /&gt;  $files = array_keys($files);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;foreach ($files as $file){&lt;br /&gt;  echo "&amp;lt;script type='\"text' /&amp;gt;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;OUTPUT:&lt;br /&gt;&amp;lt;script type='text/javascript' source='/javascript/foobar.js'&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;script type='text/javascript' source='/javascript/baz.js'&amp;gt;&amp;lt;/script&amp;gt; &lt;/pre&gt; &lt;p&gt;模板里的源代码没必要为了分别适应开发和产品阶段而改动，它帮助我们在开发时保持文件分散，发布成产品时把文件合并。想更进一步的话，可以把合并过 程（merge process）写在php里，然后使用同一个（合并文件的）配置去执行。这样就只有一个配置文件，避免了同步问题。为了做的更加完美，我们还可以分析 css和js文件在页面中同时出现的几率，以此决定合并哪些文件最合理（几乎总是同时出现的文件是合并的首选）。&lt;/p&gt; &lt;p&gt;对css来说，可以先建立一个主从关系的模型，它很有用。一个主样式表控制应用的所有样式表，多个子样式表控制不同的应用区域。采用这个方法，大多数页面只需下载两个css文件，而其中一个（指主样式表）在页面第一次请求时就会缓存。&lt;/p&gt; &lt;p&gt;对没有太多css和js资源的应用来说，这个方法在第一次请求时可能比单个大文件慢，但如果保持文件数量很少的话，你会发现其实它更快，因为每个页 面的数据量更小。让人头疼的下载花销被分散到不同的应用区域，因此并发下载数保持在一个最小值，同时也使得页面的平均下载数据量很小。&lt;/p&gt; &lt;h3&gt;压缩&lt;/h3&gt; &lt;p&gt;谈到资源压缩，大多数人马上会想到&lt;a href="http://sourceforge.net/projects/mod-gzip/"&gt;mod_gzip&lt;/a&gt;（但要当心，mod_gzip实际上是个魔鬼，至少能让人做恶梦）。它的原理很简单：浏览器请求资源时，会发送一个header表明自己能接受的内容编码。就像这样：&lt;/p&gt; &lt;pre&gt;Accept-Encoding: gzip,deflate&lt;/pre&gt; &lt;p&gt;服务器遇到这样的header请求时，就用gzip或deflate压缩内容发往客户端，然后客户端解压缩。这过程减少了数据传输量，同时消耗了客 户端和服务器的cpu时间。也算差强人意。但是，mod_gzip的工作方式是这样的：先在磁盘上创建一个临时文件，然后发送（给客户端），最后删除这个 文件。在高容量的系统中，由于磁盘io问题，很快就会达到极限。要避免这种情况，可以改用&lt;a href="http://httpd.apache.org/docs/2.0/mod/mod_deflate.html"&gt;mod_deflate&lt;/a&gt;（apache 2才支持）。它采用更合理的方式：在内存里做压缩。对于apache 1的用户来说，可以建立一块ram磁盘，让mod_gzip在它上面写临时文件。虽然没有纯内存方式快，但也不会比往磁盘上写文件慢。&lt;/p&gt; &lt;p&gt;话虽如此，其实还是有办法完全避免压缩开销的，那就是预压缩相关静态资源，下载时由mod_gzip提供合适的压缩版本。如果把压缩添加在 build过程，它就很透明了。需要压缩的文件通常很少（用不着压缩图片，因为并不能减小更多体积），只有css和js文件（和其他未压缩的静态内容）。&lt;/p&gt; &lt;p&gt;配置选项会告诉mod_gzip去哪里找到预压缩过的文件。&lt;/p&gt; &lt;pre&gt;mod_gzip_can_negotiate Yes&lt;br /&gt;mod_gzip_static_suffix .gz&lt;br /&gt;AddEncoding gzip .gz&lt;/pre&gt; &lt;p&gt;新一点的mod_gzip版本（从1.3.26.1a开始）添加一个额外的配置选项后，就能自动预压缩文件。不过在此之前，必须确认apache有正确的权限去创建和覆盖压缩文件。&lt;/p&gt; &lt;pre&gt;mod_gzip_update_static Yes&lt;/pre&gt; &lt;p&gt;可惜，事情没那么简单。某些Netscape 4的版本（尤其是4.06-4.08）认为自己能够解释压缩内容（它们发送一个header这么说来着），但其实它们不能正确的解压缩。大多数其他版本的 Netscape 4在下载压缩内容时也有各种各样的问题。所以要在服务器端探测代理类型，（如果是Netscape 4，就要）让它们得到未压缩的版本。这还算简单的。ie（版本4-6）有些更有意思的问题：当下载压缩的javascript时，有时候ie会&lt;a href="http://support.microsoft.com/default.aspx?scid=kb;en-us;823386&amp;Product=ie600"&gt;不正确的解压缩文件&lt;/a&gt;， 或者解压缩到一半中断，然后把这半个文件显示在客户端。如果你的应用对javascript的依赖比较大（htmlor注：比如ajax应用），那么就得 避免发送压缩文件给ie。在某些情况下，一些更老的5.x版本的ie倒是能正确的收到压缩的javascript，可它们会忽略这个文件的etag header，不缓存它。（thincat友情提示：尽管压缩存在一些浏览器不兼容的现象，由于这些不能很好的支持压缩的浏览器数量现在已经非常少了，我 认为这种由于浏览器导致的压缩不正常的情况可以忽略不计。这些过时的浏览器还能不能在现在流行的windows或unix环境下面安装都存在不小的问题）&lt;/p&gt; &lt;p&gt;既然gzip压缩有这么多问题，我们不妨把注意力转到另一边：不改变文件格式的压缩。现在有很多这样的javascript压缩脚本可用，大多数都 用一个正则表达式驱动的语句集来减小源代码的体积。它们做的不外乎几件事：去掉注释，压缩空格，缩短私有变量名和去掉可省略的语法。&lt;/p&gt; &lt;p&gt;不幸的是，大多数脚本效果并不理想，要么压缩率相当低，要么某种情形下会把代码搞得一团糟（或者两者兼而有之）。由于对解析树的理解不完整，压缩器 很难区分一句注释和一句看似注释的引用字符串。因为闭合结构的混合使用，要用正则表达式发现哪些变量是私有的并不容易，因此一些缩短变量名的技术会打乱某 些闭合代码。&lt;/p&gt; &lt;p&gt;还好有个压缩器能避免这些问题：&lt;a href="http://dojotoolkit.org/docs/compressor_system.html"&gt;dojo压缩器&lt;/a&gt;（现成的版本在&lt;a href="http://alex.dojotoolkit.org/shrinksafe/"&gt;这里&lt;/a&gt;）。 它使用rhino（mozilla的javascript引擎，是用java实现的）建立一个解析树，然后将其提交给文件。它能很好的减小代码体积，仅用 很小的成本：因为只在build时压缩一次。由于压缩是在build过程中实现的，所以一清二楚。（既然压缩没有问题了，）我们可以在源代码里随心所欲的 添加空格和注释，而不必担心影响到产品代码。&lt;/p&gt; &lt;p&gt;与javascript相比，css文件的压缩相对简单一些。由于css语法里不会有太多引用字符串（通常是url路径跟字体名），我们可以用正则 表达式大刀阔斧的干掉空格（htmlor注：这句翻的最爽，哈哈）。如果确实有引用字符串的话，我们总可以把一串空格合成一个（因为不需要在url路径和 字体名里查找多个空格和tab）。这样的话，一个简单的perl脚本就够了：&lt;/p&gt; &lt;pre&gt;#!/usr/bin/perl&lt;br /&gt;&lt;br /&gt;my $data = '';&lt;br /&gt;open F, $ARGV[0] or die "Can't open source file: $!";&lt;br /&gt;$data .= $_ while &lt;f&gt;;&lt;br /&gt;close F;&lt;br /&gt;&lt;br /&gt;$data =~ s!/*(.*?)*/!!g;  # 去掉注释&lt;br /&gt;$data =~ s!s+! !g;           # 压缩空格&lt;br /&gt;$data =~ s!} !}\n!g;         # 在结束大括号后添加换行&lt;br /&gt;$data =~ s!\n$!!;             # 删除最后一个换行&lt;br /&gt;$data =~ s! { ! {!g;         # 去除开始大括号后的空格&lt;br /&gt;$data =~ s!; }!}!g;          # 去除结束大括号前的空格&lt;br /&gt;&lt;br /&gt;print $data;&lt;/f&gt;&lt;/pre&gt; &lt;p&gt;然后，就可以把单个的css文件传给脚本去压缩了。命令如下：&lt;/p&gt; &lt;pre&gt;perl compress.pl site.source.css &gt; site.compress.css&lt;/pre&gt; &lt;p&gt;做完这些简单的纯文本优化工作后，我们就能减少数据传输量多达50%了（这个量取决于你的代码格式，可能更多）。这带来了更快的用户体验。不过我们真正想做的是，尽可能避免用户请求的发生——除非确实有必要。这下HTTP缓存知识派上用场了。&lt;/p&gt; &lt;h3&gt;缓存是好东西&lt;/h3&gt; &lt;p&gt;当用户代理（如浏览器）向服务器请求一个资源时，第一次请求过后它就会缓存服务器的响应，以避免重复之后的相同请求。缓存时间的长短取决于两个因 素：代理的配置和服务器的缓存控制header。所有浏览器都有不同的配置选项和处理方式，但大多数都会把一个资源至少缓存到会话结束（除非被明确告 知）。&lt;/p&gt; &lt;p&gt;为了不让浏览器缓存改动频繁的页面，你很可能已经发送过header不缓存动态内容。在php中，以下两行命令可以做到：&lt;/p&gt; &lt;pre&gt;header("Cache-Control: private");&lt;br /&gt;header("Cache-Control: no-cache", false);&lt;br /&gt;?&gt;&lt;/pre&gt; &lt;p&gt;听起来太简单了？确实如此——因为有些代理（浏览器）在某些环境下将忽略这些header。要确保浏览器不缓存文档，应该更强硬一些：&lt;/p&gt; &lt;pre&gt;# 让它在过去就“失效”&lt;br /&gt;header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");&lt;br /&gt;&lt;br /&gt;# 永远是改动过的&lt;br /&gt;header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");&lt;br /&gt;&lt;br /&gt;# HTTP/1.1&lt;br /&gt;header("Cache-Control: no-store, no-cache, must-revalidate");&lt;br /&gt;header("Cache-Control: post-check=0, pre-check=0", false);&lt;br /&gt;&lt;br /&gt;# HTTP/1.0&lt;br /&gt;header("Pragma: no-cache");&lt;br /&gt;?&gt;&lt;/pre&gt; &lt;p&gt;这样，对于我们不想缓存的内容来说已经行了。但对于那些不会每次请求时都有改动的内容，应该鼓励浏览器更霸道的缓存它。“If-Modified- Since”请求header能够做到这点。如果客户端在请求中发送一个“If-Modified-Since”header，apache（或其他服务 器）会以状态代码304（没改过）响应，告诉浏览器缓存已经是最新的。使用这个机制，能够避免重复发送文件给浏览器，不过仍然导致了一个HTTP请求的消 耗。嗯，再想想。&lt;/p&gt; &lt;p&gt;与If-Modified-Since机制类似的是实体标记（entity tags）。在apache环境下，每个对静态文件的响应都会发出一个“ETag”header，它包含了一个由文件修改时间、文件大小和inode号生 成的校验和（checksum）。在下载文件之前，浏览器会发送一个HEAD请求去检查文件的etag。可ETag跟If-Modified-Since 有同样的问题：客户端仍旧需要执行HTTP请求来验证本地缓存是否有效。&lt;/p&gt; &lt;p&gt;此外，如果你使用多台服务器提供内容，得小心使用if-modified-since和etags。在两台负载平衡的服务器环境下，对一个代理（浏 览器）来说，一个资源可以这次从A服务器得到，下次从B服务器得到（htmlor注：lvs负载平衡系统就是个典型的例子）。这很好，也是采用平衡负载的 原因。可是，如果两台服务器给同一个文件生成了不同的etag或者文件修改日期，浏览器就无所适从了（每次都会重新下载）。默认情况下，etag是由文件 的inode号生成的，而多台服务器之间文件的inode号是不同的。可以使用apache的配置选项关掉它：&lt;/p&gt; &lt;pre&gt;FileETag MTime Size&lt;/pre&gt; &lt;p&gt;使用这个选项，apache将只用文件修改日期和文件大小来决定etag。很不幸，这导致了另一个问题（一样能影响if-modified- since）。既然etag依赖于修改时间，就得让时间同步。可往多台服务器上传文件时，上传时间差个一到两秒是常有的事。这样一来，两台服务器生成的 etag还是不一样。当然，我们还可以改变配置，让etag的生成只取决于文件大小，但这就意味着如果文件内容变了而大小没变，etag也不会变。这可不 行。&lt;/p&gt; &lt;h3&gt;缓存真是个好东西&lt;/h3&gt; &lt;p&gt;看来我们正从错误的方向入手解决问题。（现在的问题是，）这些可能的缓存策略导致了一件事情反复发生，那就是：客户端向服务器查询本地缓存是否最 新。假如服务器在改动文件的时候通知客户端，客户端不就知道它的缓存是最新的了（直到接到下一次通知）？可惜天公不做美——（事实）是客户端向服务器发出 请求。&lt;/p&gt; &lt;p&gt;其实，也不尽然。在获取js或css文件之前，客户端会用 script 或标记向服务器发送一个请求，说明 哪个页面要加载这些文件。这时候就可以用服务器的响应来通知客户端这些文件有了改动。有点含糊，说得再详细点就是：如果改变css和js文件内容的同时， 也改变它们的文件名，就可以告诉客户端对url全都永久缓存——因为每个url都是唯一的。&lt;/p&gt; &lt;p&gt;假如能确定一个资源永不更改，我们就可以发出一些霸气十足的缓存header（htmlor注：这句也很有气势吧）。在php里，两行就好：&lt;/p&gt; &lt;pre&gt;header("Expires: ".gmdate("D, d M Y H:i:s", time()+315360000)." GMT");&lt;br /&gt;header("Cache-Control: max-age=315360000");&lt;br /&gt;?&gt;&lt;/pre&gt; &lt;p&gt;我们告诉浏览器这个内容在10年后（10年大概会有315,360,000秒，或多或少）过期，浏览器将会保留它10年。当然，很有可能不用php输出css和js文件（因此就不能发出header），这种情况将在稍后说明。&lt;/p&gt; &lt;h3&gt;人力有时而穷&lt;/h3&gt; &lt;p&gt;当文件内容更改时，手动去改文件名是很危险的。假如你改了文件名，模板却没有指向它？假如你改了一些模板另一些却没改？假如你改了模板却没改文件 名？还有最糟的，假如你改动了文件却忘了改名或者忘了改变对它的引用？最好的结果，是用户看到老的而看不到新的内容。最坏的结果，是找不到文件，网站没法 运转了。听起来这（指改动文件内容时修改url）似乎是个馊主意。&lt;/p&gt; &lt;p&gt;幸运的是，计算机做这类事情——当某种变化发生，需要相当准确地完成的、重复重复再重复的（htmlor注：番茄鸡蛋伺候～）、枯燥乏味的工作——总是十分在行。&lt;/p&gt; &lt;p&gt;这个过程（改变文件的url）没那么痛苦，因为我们根本不需要改文件名。资源的url和磁盘上文件的位置也没必要保持一致。使用apache的&lt;a href="http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html"&gt;mod_rewrite&lt;/a&gt;模块，可以建立简单的规则，让确定的url重定向到确定的文件。&lt;/p&gt; &lt;pre&gt;RewriteEngine on&lt;br /&gt;RewriteRule ^/(.*.)v[0-9.]+.(css|js|gif|png|jpg)$ /$1$2 [L]&lt;/pre&gt; &lt;p&gt;这条规则匹配任何带有指定扩展名同时含有“版本”信息（version nugget）的url，它会把这些url重定向到一个不含版本信息的路径。如下所示：&lt;/p&gt; &lt;pre&gt;URL      Path&lt;br /&gt;/images/foo.v2.gif -&gt; /images/foo.gif&lt;br /&gt;/css/main.v1.27.css -&gt; /css/main.css&lt;br /&gt;/javascript/md5.v6.js -&gt; /javascript/md5.js&lt;/pre&gt; &lt;p&gt;使用这条规则，就可以做到不改变文件路径而更改url（因为版本号变了）。由于url变了，浏览器就认为它是另一个资源（会重新下载）。想更进一步的话，可以把我们之前说的脚本编组函数结合起来，根据需要生成一个带有版本号的 script标记列表。&lt;/p&gt; &lt;p&gt;说到这里，你可能会问我，为什么不在url结尾加一个查询字符串（query string）呢（如/css/main.css?v=4）？根据HTTP缓存规格书所说，用户代理对含有查询字符串的url永不缓存。虽然ie跟 firefox忽略了这点，opera和safari却没有——为了确保所有浏览器都缓存你的资源，还是不要在url里用查询字符串的好。&lt;/p&gt; &lt;p&gt;现在不移动文件就能更改url了，如果能让url自动更新就更好了。在小型的产品环境下（如果有大型的产品环境，就是开发环境了），使用模板功能可以很轻易的实现这点。这里用的是smarty，用其他模板引擎也行。&lt;/p&gt; &lt;pre&gt;SMARTY:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;PHP:&lt;br /&gt;function smarty_version($args){&lt;br /&gt;$stat = stat($GLOBALS['config']['site_root'].$args['src']);&lt;br /&gt;$version = $stat['mtime'];&lt;br /&gt;&lt;br /&gt;echo preg_replace('!.([a-z]+?)$!', ".v$version.$1", $args['src']);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;OUTPUT:&lt;br /&gt;&lt;/pre&gt; &lt;p&gt;对每个链接到的资源文件，我们得到它在磁盘上的路径，检查它的mtime（文件最后修改的日期和时间），然后把这个时间当作版本号插入到url中。 对于低流量的站点（它们的stat操作开销不大）或者开发环境来说，这个方案不错，但对于高容量的环境就不适用了——因为每次stat操作都要磁盘读取 （导致服务器负载升高）。&lt;/p&gt; &lt;p&gt;解决方案相当简单。在大型系统中每个资源都已经有了一个版本号，就是版本控制的修订号（你们应该使用了版本控制，对吧？）。当我们建立站点准备部署的时候，可以轻易的查到每个文件的修订号，写在一个静态配置文件里。&lt;/p&gt; &lt;pre&gt;$GLOBALS['config']['resource_versions'] = array(&lt;br /&gt;'/images/foo.gif'    =&gt; '2.1',&lt;br /&gt;'/css/main.css'      =&gt; '1.27',&lt;br /&gt;'/javascript/md5.js' =&gt; '6.1.4',&lt;br /&gt;);&lt;br /&gt;?&gt;&lt;/pre&gt; &lt;p&gt;当我们发布产品时，可以修改模板函数来使用版本号。&lt;/p&gt; &lt;pre&gt;function smarty_version($args){&lt;br /&gt;if ($GLOBALS['config']['is_dev_site']){&lt;br /&gt;  $stat = stat($GLOBALS['config']['site_root'].$args['src']);&lt;br /&gt;  $version = $stat['mtime'];&lt;br /&gt;}else{&lt;br /&gt;  $version = $GLOBALS['config']['resource_versions'][$args['src']];&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;echo preg_replace('!.([a-z]+?)$!', ".v$version.$1", $args['src']);&lt;br /&gt;}&lt;br /&gt;?&gt;&lt;/pre&gt; &lt;p&gt;就这样，不需要改文件名，也不需要记住改了哪些文件——当文件有新版本发布时它的url就会自动更新——有意思吧？我们就快搞定了。&lt;/p&gt; &lt;h3&gt;只欠东风&lt;/h3&gt; &lt;p&gt;之前谈到为静态文件发送超长周期（very-long-period）的缓存header时曾说过，如果不用php输出，就不能轻易的发送缓存header。很显然，有两个办法可以解决：用php输出，或者让apache来做。&lt;/p&gt; &lt;p&gt;php出马，手到擒来。我们要做的仅仅是改变rewrite规则，把静态文件指向php脚本，用php在输出文件内容之前发送header。&lt;/p&gt; &lt;pre&gt;Apache:&lt;br /&gt;RewriteRule ^/(.*.)v[0-9.]+.(css|js|gif|png|jpg)$  /redir.php?path=$1$2  [L]&lt;br /&gt;&lt;br /&gt;PHP:&lt;br /&gt;header("Expires: ".gmdate("D, d M Y H:i:s", time()+315360000)." GMT");&lt;br /&gt;header("Cache-Control: max-age=315360000");&lt;br /&gt;&lt;br /&gt;# 忽略带有“..”的路径&lt;br /&gt;if (preg_match('!..!', $_GET[path])){ go_404(); }&lt;br /&gt;&lt;br /&gt;# 保证路径开头是确定的目录&lt;br /&gt;if (!preg_match('!^(javascript|css|images)!', $_GET[path])){ go_404(); }&lt;br /&gt;&lt;br /&gt;# 文件不存在？&lt;br /&gt;if (!file_exists($_GET[path])){ go_404(); }&lt;br /&gt;&lt;br /&gt;# 发出一个文件类型header&lt;br /&gt;$ext = array_pop(explode('.', $_GET[path]));&lt;br /&gt;switch ($ext){&lt;br /&gt;case 'css':&lt;br /&gt;  header("Content-type: text/css");&lt;br /&gt;  break;&lt;br /&gt;case 'js' :&lt;br /&gt;  header("Content-type: text/javascript");&lt;br /&gt;  break;&lt;br /&gt;case 'gif':&lt;br /&gt;  header("Content-type: image/gif");&lt;br /&gt;  break;&lt;br /&gt;case 'jpg':&lt;br /&gt;  header("Content-type: image/jpeg");&lt;br /&gt;  break;&lt;br /&gt;case 'png':&lt;br /&gt;  header("Content-type: image/png");&lt;br /&gt;  break;&lt;br /&gt;default:&lt;br /&gt;  header("Content-type: text/plain");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;# 输出文件内容&lt;br /&gt;echo implode('', file($_GET[path]));&lt;br /&gt;&lt;br /&gt;function go_404(){&lt;br /&gt;header("HTTP/1.0 404 File not found");&lt;br /&gt;exit;&lt;br /&gt;}&lt;/pre&gt; &lt;p&gt;这个方案有效，但并不出色。（因为）跟apache相比，php需要更多内存和执行时间。另外，我们还得小心防止可能由path参数传递伪造值引起 的exploits。为避免这些问题，应该用apache直接发送header。rewrite规则语句允许当规则匹配时设置环境变量 （environment variable），当给定的环境变量设置后，Header命令就可以添加header。结合以下两条语句，我们就把rewrite规则和header设 置绑定在了一起：&lt;/p&gt; &lt;pre&gt;RewriteEngine on&lt;br /&gt;RewriteRule ^/(.*.)v[0-9.]+.(css|js|gif|png|jpg)$ /$1$2 [L,E=VERSIONED_FILE:1]&lt;br /&gt;&lt;br /&gt;Header add "Expires" "Mon, 28 Jul 2014 23:30:00 GMT" env=VERSIONED_FILE&lt;br /&gt;Header add "Cache-Control" "max-age=315360000" env=VERSIONED_FILE&lt;/pre&gt; &lt;p&gt;考虑到apache的执行顺序，应该把rewrite规则加在主配置文件（httpd.conf）而不是目录配置文件（.htaccess）中。否 则在环境变量设置之前，header行会先执行（就那没意义了）。至于header行，则可以放在两文件任何一个当中，没什么区别。&lt;/p&gt; &lt;h3&gt;眼观六路&lt;/h3&gt; &lt;p&gt;（htmlor注：多谢&lt;a href="http://tchaikov.blogsome.com/"&gt;tchaikov&lt;/a&gt;告知“skinning rabbits”的含义，但我不想翻的太正式，眼下的这个应该不算太离谱吧。）&lt;/p&gt; &lt;p&gt;通过结合使用以上技术，我们可以建立一个灵活的开发环境和一个快速又高性能的产品环境。当然，这离终极目标“速度”还有一段距离。有许多更深层的技 术（比如分离伺服静态内容，用多域名提升并发量等）值得我们关注，包括与我们谈到的方法（建立apache过滤器，修改资源url，加上版本信息）殊途同 归的其他路子。你可以留下评论，告诉我们那些你正在使用的卓有成效的技术和方法。&lt;/p&gt; &lt;p&gt;（完）&lt;/p&gt; 原文地址：http://blog.htmlor.com/2006/08/03/serving_javascript_fast_chinese/&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/294379627880145984-4607370990288810744?l=netfishx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://netfishx.blogspot.com/feeds/4607370990288810744/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=294379627880145984&amp;postID=4607370990288810744' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/294379627880145984/posts/default/4607370990288810744'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/294379627880145984/posts/default/4607370990288810744'/><link rel='alternate' type='text/html' href='http://netfishx.blogspot.com/2007/01/flickrjavascript.html' title='（转贴）flickr对javascript干的好事'/><author><name>netfishx</name><uri>http://www.blogger.com/profile/15593804318935689524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
