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