biaoge's blog

以前端技术为主

前端MVC之Backbone.js

without comments

Written by admin

February 25th, 2012 at 12:57 am

Posted in 前端技术

前端代码的本地化开发

with 5 comments

如果网站的后台是PHP或者JAVA的,那么搭建本地开发环境并不是什么难事,可是由于我们大部分站点的后台语言是C++写的cgi程序,服务器是Linux,所以cgi都是在Linux下编译的,而我们的开发机器是windows,因此对我们来讲,搭建本地开发环境比较困难。所以一直以来都是所有的前端开发人员都是在一个由samba搭建的Linux共享磁盘里面进行开发。

随着团队人数的增加,多人在共享磁盘里面开发的弊端越来越明显。首先是代码很难用版本控制工具进行管理,由于samba的效率问题,在多人使用的samba共享目录里面操作SVN非常痛苦,更新和提交操作的速度很慢,经常卡死,后来不得已直接取消了在开发环境用SVN进行版本管理。但是没有版本管理之后很容易造成代码的丢失或者被他人覆盖,毕竟是多人共用的磁盘,出现任何情况都有可能,所以经常要手动备份代码,这对于大部分开发人员来说是一个痛苦的过程。共享磁盘开发的另一个弊端是,有些同事开发了一个功能只完成了一半导致流程中断不能继续下去,妨碍其他同事的工作。

所以最近我们又开始讨论本地化开发的问题,如果采用本地开发就可以大体上解决上面的两个问题。在本机使用版本管理,代码更容易追踪,谁在什么时间修改了什么代码可以看得一目了然。经过团队内部的讨论得到如下基本可行的本地开发方案:

所需要的工具和前提条件:

1.TortoiseSVN和一个前端代码的版本库

2.Plink及开发服务器的SSH账号

3.Fiddler + Willow(感谢YuniShi)

4.本机安装Apache

我们前端代码基本上都在htdocs和template两个目录里面。htdocs里面主要是静态HTML、CSS,JS和图片等,当然HTML不能算全静态的,其中用到了Apache的SSI指令。template目录里面全部是cgi的模版文件。

本机安装好Apache之后,将前端代码(htdocs和template)checkout到本机,htdocs设置为Apache的根目录,由于htdocs里面都是静态文件,只要Apache开启了SSI指令,完全可以通过本机的Apache来访问。所以配host www.domain.com 127.0.0.1即可。

template里面的代码可以必须通过服务器的cgi来解析,因此不可能通过本机的Apache来访问。解决方法是在开发服务器上checkout一份前端代码的工作副本,将所有的cgi请求发送到服务器,服务器上的cgi解析的也是服务器上的template里面的模版。这里会有两个问题:一、访问静态文件的域名和访问cgi的域名是同一个,如何将静态文件请求发送到本机Apache而将cgi的请求发送到服务器?这个时候Fiddler + Willow就派上了用场,由于所有的cgi都在/cgi-bin/这个目录中,通过Willow的针对文件夹配host的功能就可以将所有cgi的请求发送到linux开发服务器。下图中通过Willow的Host list将www.tenpay.com和img.tenpay.com两个域名指向本机ip:127.0.0.1,然后通过一个extension将所有/cgi-bin/目录的hosts配置到开发服务器:

第二个问题是cgi访问的是linux服务器上的template目录的模版文件,如何谈得上是本地开发?我们修改的其实是本地的模版文件然后通过SVN钩子自动同步到服务器上。原理是这样的:我们给本机的SVN工作副本设置一个post-commit钩子,就是一个批处理文件,我们修改完模版文件需要看效果的时候就做一次SVN提交操作,提交操作会触发这个post-commit钩子,而这个钩子的作用就是通过Plink的SSH连接到服务器并更新服务器上的SVN工作副本。SVN钩子的设置方法见下图:

钩子设置完毕之后整个设置过程就OK了,这个时候在浏览器打开www.domain.com(开启Fiddler)会发现所有的静态文件都请求了本机的服务器,而所有的cgi请求发送到了开发服务器,如果修改静态文件,直接刷新浏览器就可以看效果,如果修改了模版文件则需要提交一下SVN再刷新看效果。

Written by admin

September 9th, 2011 at 12:02 am

Posted in 前端技术

JS模版引擎jTemplate介绍

without comments

Written by admin

April 26th, 2011 at 1:10 am

Posted in 前端技术

好的拖延和坏的拖延

with one comment

原文:Good and bad procrastination

这是Paul Graham的一篇文章,感觉写得不错,前几个星期翻译了一部分,一直放在电脑里面没发出来,本来以为《黑客与画家》这本书里面会收录这篇的,结果在英文PDF里面一搜发现居然没有,索性整理了一下发布出来。《黑客与画家》已经在当当买了,还没收到,推荐这本书。

我所知道的那些令人钦佩的人全部是严重的拖延者。这是否说明拖延并不总是坏的?

许多人写的关于拖延的问题都是在写如何克服它,但这,严格来讲,是不可能的。你总是有无数的事情可以做,当你做其中一件,你就没有机会去做其他任何一件。所以问题不是如何避免拖延,而是如何正确地拖延。

取决于你所做的事情,拖延共有三个变体:你(a)啥也没做,(b)做了些不重要的事情,或(c)做了重要的事情。最后的那种,我觉得,是好的拖延。

有一种“心不在焉者”,当他思考一些有趣的问题的时候,他会忘记刮胡子、吃饭、甚至忘了看路,他的思维在日常生活中消失了,因为它在另一个世界中努力工作。

这就是为什么我认识的一些很令人钦佩的人全都是拖延者。他们都是C类的拖延者:他们放下一些小事情去做大事情。

什么是“小事情”?大致来讲,就是没有可能出现在你的讣告中的那些工作,目前来讲我很难说你将做出的最大的成就是什么(会不会是你在苏美尔寺庙建筑上的代表作?或者你用笔名写的一部惊悚侦探小说?),但是有一类任务你是可以毫无顾虑地排除掉的:刮胡子、洗衣服、打扫房子、写感谢信——所有类似这样的小差事。

好的拖延就是避免做小事情而投入到真正的工作中去。

这种拖延至少从某种意义上来讲是好的。那些想让你去做这些小差事的人可不这么认为,但如果你想做点重要的事情你很可能不得不得罪他们。即使是那些相当随和的人,当他们想完成一些重要工作的时候,都会为了避免小差事而表现出一定程度的冷酷。

某些差事,类似回信这种事,如果你忽略它它就会消失(可能是连同你的朋友一块消失)。其他一些,如修剪草坪、填写纳税申报表,如果延期只会变得更坏。原则上,拖延第二种类型的差事是没用的,因为最终你还是得做掉它。为什么不现在就做呢(像过期提醒上说的那样)?

即便这种类型的小差事也值得延期的原因是完成重要工作所必需的两个要素小差事并不需要:大片大片的时间,和良好的心境。如果你从某个项目得到了灵感,那么砍掉几天之内所有要做的事情来专心做这个项目是完全值得的。是的,当你后来再处理那些小差事的时候会耗费你更多的时间,但是如果你在那几天内完成了不少重要的事情,总体来讲你的效率是更高的。

事实上,这不是程度上的差别,而是类型上的差别。某些类型的工作只能在灵感到来的时候,大块的、不间断的时间段内完成,而不能严格按照每天安排好的碎片时间完成。从经验上来看也是如此,当我想到我认识的做出过伟大成就的那些人,我无法想象他们是尽职尽责地从待做清单上划掉一个又一个任务,而是想象他们把自己闭关起来去实现他们的新想法。

相反地,强迫某人及时地完成小差事一定会限制他们的工作效率,一个干扰的代价不是它所占用的时间,而是他把完整的时间切成了两段,你很可能一天只要打断某个人几次,他就完全没法搞定任何困难的问题了。

我很好奇为什么当创业公司最开始只有几个人挤在一个小房间里的时候效率反而是最高的。最重要的原因可能是这时还没有人打扰他们。理论上,创始人后来有足够的钱雇人来帮他做事情是件好事,但也许即使操劳过度也好过被打扰。一旦你给一个创业公司注入了一些普通的公司职员——B类拖延者之后——整个公司就开始按照他们的节奏运转了,他们是干扰驱动源,很快你也变得跟他们一样。

小差事能轻易地干掉重大的项目,不少人专门把它用做这个目的呢。比如,当某人决定开始写部小说的时候,突然发现房子需要打扫。那些写小说失败的人往往并不是坐在一张白纸前好几天写不出任何东西,他们或喂猫,或去买他们房间里面需要的东西,或和朋友喝咖啡,收E-mail。“我没时间工作”,他们说。他们当然没时间,那是他们自找的。

(还有一种变体是他们没地方工作。解决此问题的办法是去参观伟人工作过的地方,看看他们和他们的工作环境是多么不相称。)

这两个借口我有时也用过。在过去的20年内我学了不少技巧让自己保持工作的状态,但即使是现在我也不是总能达到目的。有时候我能完成重要的工作,有时候我的时间被小差事给吞噬。我知道这常常是自己的错:我让小差事把一天时间给吞并了,而没能去解决困难的问题。

最为严重的一种拖延是还未意识到的B类拖延,因为它看起来不像拖延。你“做了些事”,不过做了些错事。

所有关于拖延的建议中,如果他们关注的是如何从待做清单上划去一些条目而未考虑到待做清单本身就是一种B类拖延的可能性,那么他们不仅是不正确的,而且是积极误导。事实上,可能性这个词语气太弱了,几乎所有的清单都是。除非你在做你可能做的最重大的事情,否则不管你完成了多少任务,你都是在进行B类拖延。

Richard Hamming在他的著名的论文《你和你的研究》(我把它推荐给所有有抱负的人,不管你的工作是什么)中建议你问自己三个问题:

1.你的领域内最重要的问题是什么?

2.你是否在研究这些问题中的一个?

3.为什么没有?

Hamming在贝尔实验室的时候开始问自己这些问题。原则上,任何人都应该能研究他们领域内最重要的问题,也许不是每个人都能在世界上写下浓墨重彩的一笔,我不知道,但是不论你能力大小,总有些项目能够增强你的能力。所以Hamming的练习可以概括成:

你能做的最合适的事情是什么,为什么没做?

许多人逃避这个问题,我自己也逃避过。我看到了这个问题之后迅速读了下一句。Hamming曾经四处问别人这个问题,这并没有让他备受欢迎。但这个问题是每个有进取心的人都应该面对的。

现在的问题是,你可能最后用这个诱饵钓到一条大鱼,但要做合适的工作,你要做的不仅仅是寻找好的项目。一旦你找到它们,你要能让自己参与进去,这可能很困难。问题越重大,让自己参与进去的难度也越大。

当然,人们很难参与到某个特定问题中去的一个重要原因是他们发现自己并不感兴趣。尤其是当你年轻的时候,你常常发现自己在处理一些不感兴趣的工作——可能因为那个工作看上去引人注目,或者因为这是分配给你的作业。许多研究生常常被卡在研究他们不感兴趣的重大问题上,所以研究生院成了拖延的同义词。

但即便你喜欢自己的工作,你还是容易让自己去处理小问题而不是大问题。为什么?为什么让自己去处理重大问题如此困难?原因之一是在短期内你可能得不到任何回报。如果你解决掉在一两天内能解决的问题,你很快就能得到成就感。如果在无尽遥远的未来才能得到回报,你会觉得不太真实。

人们不参与重大项目的另一个原因是,很讽刺地,害怕浪费时间。如果失败了怎么办?那么花在上面的所有时间都会浪费掉。(实际上很可能不会,因为处理困难项目几乎都是有所回报的)

但是处理重大问题的障碍还不仅仅是它们没有即时的回报和可能浪你费大量的时间。如果那就是全部,它们不会比拜访你的姻亲坏到哪去。但还有其他的麻烦,重大的问题令人恐惧,面对它们的时候甚至有生理上的疼痛,就像又一个真空吸尘器吸住了你的想象力,所有最初的想法立即被吸走了,然后你没了其他的想法,而吸尘器还在继续吸。

你不能太正视重大的问题,你需要拐弯抹角地靠近它,但你得把角度调对:你需要足够正视它,直到你能体会到它所辐射出来的令人兴奋的东西,但不要到达到让它使你瘫痪的程度。一旦你开始做了之后你就可以把角度调正一点,就像航行中的帆船可以离风更近一点。

如果你想攻克重大的问题,你似乎不得不欺骗自己去做它。你必须先处理能够转变成大问题的小问题,或者处理一个比一个大的问题,或者把事情拆分和同伴一起分担。依赖这些技巧并不意味着你很差,许多很棒的工作都是通过这种方式来完成的。

当我和那些让成功使自己参与到重大问题的研究中的人讨论时,我发现他们都砍掉了小差事,并都为此有负罪感。我不认为他们应该有负罪感,每个人都有做不完的事情,所以一个人做了他最应该去做的事情时必定留下一堆做不了的小差事,他们对此感觉不好似乎是错误的。

我觉得“解决”拖延问题的办法是让兴奋来拉动你,而不是用一个待做清单来推动你。参与到一个你真正喜欢的有抱负的项目中,乘风破浪,杨帆远航,然后你自然就能放下那些不该做的事情。

Written by admin

April 22nd, 2011 at 11:46 pm

Posted in Lifehack

读稻盛和夫的《活法》

without comments

最近两三天读完了稻盛和夫《活法》。我平时看书不多,读日本人写的书应该是第一次了。这本书主要讲的是稻盛和夫的人生哲学和经营理念,类似于励志书籍,不过因为出自稻盛和夫这样一个亲手创办了两个世界500强的企业家之手就比一般的励志书更有说服力了。整本书读完发现稻盛和夫尤其重视东方传统文化以及伦理道德的宣传。

就我个人来讲,不知道是从小被被应试教育毒害太深还是脑子不开窍,对中国古代的文化一直是持比较抵制的态度,总是提不起兴趣,并且觉得也没多大用处。以至于现在我的各种思想观念越来西方化,越来越有崇洋媚外的倾向,当然和从事的职业也有关系,毕竟在计算机行业西方的技术实力一直是遥遥领先于东方的。

但是在读《活法》的过程中我发现原来东方的哲学在稻盛和夫的人生中占有这么重要的地位,几乎从头到尾稻盛都在强调当他遇到困难的事情不知道如何抉择的时候他就会问自己:“什么是正确的做人准则?”,这个方法不论在为人处事,经营企业或者处理国际问题都同样适用。他的这种哲学其实源自王阳明的学说,连一个日本人都时刻以王阳明的哲学严格要求自己,而我对它居然一无所知,实在是有点惭愧。于是在百度百科上看了一下王阳明的”心学”,才明白什么是“心即理”,什么是“致良知”,什么是“知行合一”。“心即理”是指最高的道理不需外求,从自己的心里即可得到。良知人人具有,个个自足,是一种不假外力的内在力量。“致良知”就是将良知推广扩充到事事物物。“致良知”也就是知行合一。“良知”是“知是知非”的“知 ”,“致”是在事上磨炼,见诸客观实际。“致良知”即是在实际行动中实现良知,知行合一,仅仅是知道还不够,一定要去做,去实践。稻盛和夫正是不折不扣地将这种哲学运用到自己的人生中。

另外一点书中多次提到“精进”。精进是指:专心致志于眼前所从事的工作,付出不亚于任何人的努力。他认为这是提高自我身心修养,砥砺人格的最重要、最有效的方法。当今社会的主流观点是劳动仅仅是谋生的手段,终归是令人不愉快的,因此应该尽可能避免,要想办法少劳而多获,持这种观点的人,常常有很多挣扎,想取得成就,想实现目标,却又不愿付出必须的努力,总想找捷径,有时即便在付出努力之后也患得患失,生怕没有获得应得的回报。而稻盛和夫则反其道而行之,认为劳动本身就能磨练自己的心智,升华自己的人格,因此根本不存在没有回报这回事,也就不会吝啬自己的付出,做任何事都能全力以赴,在过程中寻找喜悦和成就感。更重要的是,只有持续保持精进,才能将不可能变为可能。稻盛和夫说:“好像我们拼命努力、苦苦摸索的样子,让神灵动了恻隐之心:‘既然你如此拼死努力,我就帮帮你吧。’因此我经常激励员工:‘要努力到神灵出手相助的地步。’”

还有书中讲到的在实现梦想、达成目标的时候要有“强烈的渴望”,“坚定的信念”,反复在头脑中想象直到能“看得见”实现目标的样子,你的现实不过是内心意念的投影,你的幸运或不幸都是你的内心吸引过来的,还有所谓“智慧的宝库”,必须常怀感激之情等等,这些东西都不是第一次看到,许多说法和拿破仑·希尔的《思考致富》里面说的如出一辙,还有“吸引法则”也这么讲,而且我曾经对这些法则很着迷。这些听起来好像有点唯心主义,有些玄乎,但是经过稻盛和夫一说更令人信服了,我也越发相信如果能善用这些法则就能产生意想不到的神奇作用。

Written by admin

April 16th, 2011 at 10:28 pm

Posted in Lifehack,读书

很讨厌osx的字体平滑处理

with 5 comments

最近开始使用Macbook pro,可是发现极不喜欢osx的字体渲染方式。关于苹果和微软的字体渲染方式,阮一峰翻译的Joel的《字体平滑,反锯齿,和次像素渲染》讲得比较清楚,两家公司渲染方式的根本不同之处在于指导思想:

* 苹果公司通常认为,字体算法的首要目的,是尽可能多得保持原始设计的样子,即使有损屏幕显示的清晰性,也在所不惜。

* 微软公司通常认为,字体的形状一定要适应像素的限制,要保证屏幕显示不模糊、容易辨识,即使字体的形状因此背离原始设计,也在所不惜。

在我看来,从LCD显示屏的显示效果来讲微软的效果明显好于osx的,osx的字体很模糊,看起来有种发霉了的感觉,让人很不舒服,英文字体还勉强能接受,中文字体就很难接受了。而windows下的文字就清晰得多,更易于辨认,尤其是win7里面的微软雅黑相对与以前的宋体好看了很多。关于两种渲染方式的PK,仁者见仁,智者见智,也有人喜欢osx的平滑处理,不过我在各种论坛都发现又不少人和我一样很不习惯osx的模糊字体,在这一点上我毫不犹豫地和Jeff AtwoodDave Shea一样站在windows一边。

于是我找了各种方式来去掉osx的字体平滑处理,最后发现最简单的方式是用Tinker Tool做两个处理:在Font Smoothing标签内改成针对144px以下的文字关掉平滑处理,然后把平滑模式调成Light。这样调整之后还是有问题,一个是系统的默认英文字体Lucida Grande是无法关掉平滑处理的,所以无论如何去除得并不彻底,另一个问题是不知道什么原因某些中文字体变得很难看,而且大部分中文字也是无法去掉平滑处理的,这样一来有些中英混排的文字看上去就非常怪异。最后我的处理方式是仅作一项调整:把平滑模式调成Light,这是目前来看最能接受的一种方式。

总之从使用Mac以来,字体是我遇到的最纠结的一个问题,一直听说苹果的设计师很有品味,但这次我实在无法把osx的字体渲染方式和高品味联系起来,也不太理解为什么有人会喜欢这种效果,也许真是萝卜青菜,各有所爱。不知道新的Lion系统有没有针对字体渲染方式做一些改进,如果还是保持原状那可就比较郁闷了。

Written by admin

March 16th, 2011 at 1:12 am

Posted in Uncategorized

Web标准化交流会上分享OOCSS

without comments

Written by admin

December 25th, 2010 at 1:02 am

Posted in 前端技术

读《乔布斯管理日志》

with one comment

在读《乔布斯管理日志》这本书之前对乔布斯的印象主要来自他2005年在斯坦福大学的演讲,演讲的视频和文字都看过好几遍,并且把演讲内容转载到了博客里面,印象深刻,2007年想要改行做网站开发的时候若不是受这个演讲的影响,真不知道会不会有勇气真的去做。以下是我读完《乔布斯管理日志》后的一些感想。

1.不要忘记梦想,要有跟随内心和直觉的勇气。

在斯坦福的演讲中,有这样一段话:

“在过去的33年里,我每天早晨都对着镜子问自己:‘如果今天是我生命中的末日,我还愿意做我今天本来应该做的事情吗?’当一连好多天答案都否定的时候,我就知道做出改变的时候到了。提醒自己行将入土是我在面临人生中的重大抉择时,最为重要的工具。因为所有的事情——外界的期望、所有的尊荣、对尴尬和失败的惧怕——在面对死亡的时候,都将烟消云散,只留下真正重要的东西。在我所知道的各种方法中,提醒自己即将死去是避免掉入畏惧失去这个陷阱的最好办法。人赤条条地来,赤条条地走,没有理由不听从你内心的呼唤。”

人容易在琐碎的生活中迷失自己,忘记对自己真正重要的东西,然而一个经常用死亡来提醒自己的人不会忘记梦想。乔布斯在年轻的时候经常挂在嘴边的一句话“改变世界”,在他人到中年的时候真的做到了。

2.聚焦和做减法

97年乔布斯返回苹果公司以后开始采取减法行动。当时苹果公司的研究项目从350项减至50项,乔布斯则进一步减至10项左右。乔布斯说过:“人们认为聚焦意味着对必须重视的事情说是,但聚焦根本不是这个意思,它的意思是要对现有的另外100个好主意说不。”

颠覆性的公司不是靠数量取胜,而是靠杀手级的产品取胜。打造一个精品远胜过制造100个平庸的产品,在苹果的困难时期,一个小小的iPod就能扭转局面,因此应该把精力放在如何打造精品上。多则滥,少则精!

做减法不仅对团队重要,对个人同样如此。有时一段时期内我会给自己安排好几件事情,好像都很重要,这也想做,那也想做,其结果往往是一件也做不好。人的精力有限,难以同时做好多件事情,所以重要的事情不在多,选一件就好,然后对其余的说不。

李小龙的一句话说得很精辟:“It’s not daily increase but daily decrease—hack away the unessentials!”

3.创新、冒险精神、拒绝停滞不前

苹果公司生产了许多伟大的产品,也同样生产过不少失败的产品,我觉得这是一种必然。创新和冒险是一对孪生兄弟,创新意味着去探索未知的领域,因此一定会有失败的风险。没有冒险精神,就没有创新,更不会产生革命性的产品。

乔布斯钦佩鲍勃·迪伦的一个重要原因是他拒绝停滞不前,一生都在尝试创新和经受失败。

4.完美主义者

甲骨文的CEO拉里·埃里森说:“当年我和乔布斯是邻居的时候,他一件家具也没有。乔布斯竟然找不到符合自己要求的家具,我挺意外的。如果不达完美他宁愿不添置任何东西。”

另一件事,NeXT的一位设计师问:“谁会真的去看计算机的内部呢?”乔布斯回答说:“我会!”还有前一段时间看到乔布斯发的一条twitter,因为一名员工说不能把nano做得更小而被解雇。(此Twitter账号是别人冒充的Jobs,已被twitter停用)

他永远是这么不可思议的高标准。

5.为追求高品位不惜代价

1985年,NeXT创立后,用于公司运作的的花费已经很高了,办公室也装修得很有品位,但乔布斯还是毫不犹豫地拆掉了原有的设计,重新装修。他的理由是:“如果不首先创造一个适合思考和工作的理想环境,怎么谈得上创造真正伟大的产品?他们需要的是灵感!要设计出高品位的产品,首先要接触高品位。”

6.禅修、冥想、斋戒和节食

这似乎与乔布斯的形象反差较大,很难想象一个放荡不羁,被称为IT界的摇滚歌星式的人物会喜欢这些东西。他本人脾气暴躁、没有耐心,却又在佛学和禅道中寻求内心的宁静,这是他性格中矛盾的一面。

不知道进行禅修是否在有助于他取得事业上的成功,这一点上他本人好像也没有给一个明确的说法,但至少在我的印象中禅学里面讲的都是一些晦涩难懂又没多大用处的东西。可能是我了解得太浅了,在这方面有必要多研究研究。

7.右脑管理模式和情感经济

乔布斯和盖茨分别代表了两种管理方式的极端:盖茨是左脑模式——理性经济、偏重技术、贩卖标准,而乔布斯则是右脑模式——感性经济、偏重设计、贩卖梦想。

乔布斯一直批判硅谷只重视技术的传统做法,在他看来,“情感的经济”将取代“理性的经济”。比如,1998年的iMac、2001年的iPod,乔布斯以自己的行动告诉IT产业,基于硅芯片上的技术运算制胜时代已经过去,取而代之的是“与消费者产生情感共鸣”、“制造让顾客难忘的体验”。当产品能召唤起消费者情感,它便驱动了需求,这比任何一种差异化策略更有力量。

8.做伟大的、革命性的产品容易激发人的潜能

我很好奇是什么样的力量在驱动他几十年来勤奋工作,坚持不懈,最终收获成功。可以肯定金钱排除在外,据他的朋友拉里·埃里森说他是一个不愿意受金钱驱动的人,况且第一次创业成功之后他已经不缺钱花了。他常说的一句话是“改变世界”,再看这两句名言:

“成为墓地里最有钱的人对我没什么吸引力。夜半上床时,对自己说:你做了些了不起的事情。这对我很重要。”

“人这辈子没法做太多事情,所以每一件都要做到精彩绝伦。因为,这就是我们的宿命。人生苦短,你明白吗?所以事情最好能够他妈的干的漂亮一点,让自己觉得还算对得起自己。”

可见做了不起的、革命性的、能影响世界的产品,这不仅是乔布斯最大的动力,同时他还用这种“干的漂亮点”的哲学影响苹果公司员工,这些哲学又成为他们的工作动力,成为苹果公司的基因。

Written by admin

November 23rd, 2010 at 11:20 pm

Posted in Lifehack,读书

优化HTML

with 7 comments

  1. 为何要保持标签整洁
  2. 一团糟的写法
  3. 附加的优化方法
  4. 激进的优化方法
  5. 物极必反
  6. 反面教材
  7. 工具
  8. 将来的考虑

为何要保持标签整洁

客户端的优化近来倍受关注,可是有些较基本的方面却被忽视。如果你仔细观察某些页面(即便是那些本来应该深度优化的页面),很容易就能在他们的标签中找到一大堆冗余的、不高效的结构。所有这些累赘给本来应该尽可能保持轻量级的页面增加了不必要的负担。

保持文档整洁的原因不一定是为了更快的加载速度,更是为了让我们的建筑能有一个结实而牢固的基础,整洁的标记意味着更好的可访问性,更方便的维护,更易被搜索引擎检索,更小的体积仅仅是保持文档整洁的一个附加属性,也是我们应该这样做的另一个理由。

这篇文章里面,我们来瞧瞧html该如何优化:去掉一些不好的标记习惯、通过删除冗余的结构来减小文档体积,并应用压缩技术,我们来瞧瞧现有的压缩工具,并分析他们做得好和做得不好的地方,我们也会探讨一下在将来可以怎么做。

一团糟的写法

来看看有哪些最容易犯的错误

1.在script标签内放html注释

当今一个最严重的冗余代码是在script标签内放置HTML注释——<!-- -->,这里不需要说得太多,一句话足够:需要通过这种方式来阻止错误的浏览器(例如‘95 Netscape 1.0)几乎灭绝了,脚本内的注释是完全不必要的累赘,应该被毫不留情地删除掉。

2.<![CDATA[ … ]>

另外一种常见但是不必要的阻止错误的方式是将CDATA块放到script标签内:

<script type="text/javascript">
    //<![CDATA[
      ...
    //]]>
</script>

这个神圣的目标不切实际。尽管CDATA块是一个阻止XML解析器将<&当成标签的开头的一个很好的方式,但是只有在真正的XHTML文档(被当成“application/xhtml+xml” content-type来处理的文档)内才有效。目前大部分的网页仍然被当成“text/html”来处理的(因为,举个例子,IE目前仍然不支持 XHTML),所以他们都被当成HTML来解析,而不是XML。

除非你已经把文档当成"application/xhtml+xml"来处理,否则几乎没有任何理由把CDATA块放在里面,即便你打算以后使用XHTML,也有必要先把这些不必要的东西去除,等到真正需要的时候再加进来。

当然,一个终极的解决方案是完全避免使用内联的script标签(为了利用外部script的缓存机制)。

3.类似onclick="…", onmouseover=""这些

html事件属性有一些合理的应用场景,比如为了性能上的考虑或者为了应付古老的浏览器(尽管我还没有发现只支持html事件属性注册方式——onclick="..."而不支持dom节点属性注册方式element.onclick = ...的情况)。除了一些众所周知的拒绝它们的理由如行为和内容的分离或者便于重用,它还会污染html标记。把事件逻辑转移到外部的脚本里面,我们可以充分利用脚本的缓存机制。事件处理逻辑不必在每次的页面请求中都被传送到客户端。

4.onclick="javascript:…"

javascript 中一个很有趣的怪现象:javascript:伪协议和html事件属性处理器混合成了这样一个怪胎(发生的几率高达106,000 (!)),事实上html属性上的事件处理器会整体变成一个函数体,然后这个函数变成一个事件处理程序(通常,会先把函数的作用域加强来包含元素本身和它的部分或全部的父级)。“javascript:” 这部分变成了一个不必要的标签并且几乎没有任何作用。

5. href="javascript:void(0)"

继续javascript伪协议,有一个很著名的代码片段:href=”javascript:void(0)”,他的作用是阻止链接的默认行为。当javascript被禁用、不可用或出错的时候这个糟糕的写法使得链接完全不可访问。毫无疑问最理想的处理方法是将合适的url写入href里面,然后通过事件处理器来阻止链接的默认行为。另一种情况,如果链接是动态创建之后插入到页面中(或者最初是隐藏的,然后才通过 javascript让其显示),使用href=”#”比用javascript:更整洁,更快速。

6.style="…"

使用style属性并没有什么太严重的错误,只是如果把它里面的内容转移到一个外部的样式表里面,我们就能利用到源代码的缓存机制。这跟前面提到过的 html属性事件处理器类似。即便你只是为了给一个特定的元素设定样式并且没有打算重用它们,这些样式信息会在每次页面被请求的时候都传送一次。把样式转移到外部样式表里面能防止这个,因为外部样式表传送一次之后会缓存到客户端。

7.<script language=”Javascript” … >

也许一个最搞不懂的属性就是script标签的language属性,这个古老的属性早在1999年、10年前官方推荐HTML 4.01标准的时候就被抛弃了,除非在必须指定javascript版本(这个也不太可靠,应该尽可能避免)这种极少的情况下,否则没有任何理由继续使用这个属性。

8.<script charset=”…” … >

另一个搞不懂的属性是script的charset属性,有时候我会见到下面这种结构:

<script type="text/javascript" charset="UTF-8">
    ...
</script>

这里要说的是charset属性只放在“外部”script标签(有写src 属性的script标签)上才有意义。HTML 4.01 甚至说:

注意charset属性指定了src属性所指定的脚本的字符编码;它不关心script标签的内容。

测试表明浏览器都遵循了这条标准。

搜索一下这个结构,出现了2000次。当你发现像Textmate这些流行的编辑器里面都错误地使用了charset之后就一点都不觉得奇怪了。

9. 附加的优化方法

刚才我们说到了一些应该避免的不好的写法,但是还有一些,那就是删除冗余的部分。下面提到的一些优化是有些争议的,因为他们主要出于体积上的考虑。所以我把它们放在这里不是作为建议,而是作为一种选择。请各位三思而行。

1. <style media=”all” …>

HTML 4.01定义了style上的media属性,用来指定特定的媒介——屏幕、打印机、手持设备等等。media的一个可能的值是all,这个值恰好是现代浏览器的默认值,如果你发现自己在使用media="all",那么你可以省去它,让浏览器自动帮你设置

有趣的是,HTML 4.01说media的默认值是"screen"。但是我测试的每一款浏览器都没有按照这条标准来执行,而把默认值设定成了"all"。这可能就是为什么HTML5草案把默认值指定为"all",来和浏览器的行为达成一致。

2.<form method=”get” …>

另一个默认值——GET——form 的"method"属性常常是被明确设定的。其实除了不够清晰,省去它没有其他坏处。注意HTML 5草案没有更改这个行为

3. <input type=”text” …>

INPUT元素的type属性默认值为"text"——在HTML 4.01HTML 5草案里面都是如此。去掉这个属性对有很多文本输入框的页面来说能减少很大一部分体积。

4.<meta http-equiv=”Content-type” …>

指定页面的字符编码总是给人很大的困惑。和我们想当然的相反,META元素上指定的Content-type没有 HTTP头里面指定的“Content-type”的优先级高。当二者(HTTP头和META元素)都被设定的情况下,HTTP头优先。

如果你能控制服务器返回并且能够正确地设定HTTP头的Content-type,那么省略META标签也是可以的。保留它的唯一原因是为离线浏览该页面的时候指定编码。

5.<a id=”…” name=”…” …>

把”name”属性和”id”属性一起使用的主要原因是为了兼容古老的浏览器(如Netscape 4)。他们不能链接到用“id”指定的锚点,所以必须设置”name”,如果你的页面有有元素既设置了”id”又设置了”name”,并且不在意这些古老的浏览器,那么你可以摆脱这个古老的写法了。

注意一些副作用。如果你在脚本中通过name来查询元素(document.getElementsByNamedocument.evaluatedocument.querySelectorAll等等)把name替换成id可能会把事情搞砸。还要记住document.anchors只返回带有name属性的元素

6.<!doctype html>

一年多以前,Dustin Diaz建议使用HTML 5文档类型,作为减少页面体积的一个途径。这不是一个重要的优化方式,但是如果你不在乎是否通过检验并且需要使页面尽可能小巧,使用<!doctype html>是一个可行的备选方案。测试表明这个奇特的文档声明可以触发大量的浏览器的标准模式。

激进的优化方法

如果你渴望更多的,这里还有一些比较极端的方法。有一些(如略去选填的标签)已经出现过一段时间了,还有些之前没出现过。尽管这些做法看起来有些唐突,但是它们都可以通过检验,如果你的页面是HTML的而不是XHTML的。但是你的页面是HTML的,不是吗?;)

  1. 去掉HTML注释
  2. 去掉/减少空格
  3. 省去选填的结束标签(<p><p>foo)
  4. 如果允许,去掉属性值的引号 (<p class="foo"><p class=foo>)
  5. 删除布尔类型的属性的选填值(<option selected="selected"><option selected>)
  6. 转移内联样式、内联脚本、和html事件属性 (如果不能删掉它们的话)
  7. 转移class和id(需要同步修改脚本和样式)
  8. 把URL的协议名称去掉 (http://example.com//example.com)

但我们可以压缩

当页面压缩之后这些优化还有意义吗?难道gzip不是已经把这些冗余的标记都搞定了吗?毕竟,我们说的是一个文本格式的东西。

用处还是有的!

首先,必须清楚不是每个人都能gzip,这是很悲哀的事情,但好的一面是在这种情况下HTML 优化的意义就更大了。

其次,即便页面压缩了,我们还可以节省5-10kb(平均每个页面)。在比较大的页面中还可以节省得更多。尽管看上去也没有太多,但实际上每一个字节都很重要

作为一个压缩大型页面的例子,我优化了一下非官方的ECMA-262, 第三版规范的HTML版本,这个页面最初为750KB(gzip之后为131KB),优化之后为606KB(gzip之后115KB)。也就是说gzip之后节省了16KB,仅仅是去掉空格、注释、属性值的引号、选填标签。你可以看看这个压缩后的版本和以前的版本看起来是一模一样的。

最后,像去除空格和注释这样的优化能使得文档树更轻量,潜在地增强了页面的渲染效率。

物极必反

像其他一些优化一样,我们很容易矫枉过正。HTML Compact 就是HTML压缩工具里面做得太过的一个例子,这个优秀的windows程序用了一种很“独特”的方式来压缩HTML——用javascript把内容写入到页面中。

把这个完美的页面:

<html>
<head>
    <title></title>
</head>
<body>
    <div>
    <ul>
        <li>foo</li><li>bar</li><li>baz</li>
        <!-- few more dozens of list elements ... -->
    </ul>
    </div>
</body>
</html>

变成这副模样:

<!--hcpage status="compressed"-->
<html>
<head>
  <SCRIPT LANGUAGE="JavaScript" SRC="hc_decoder.js"></SCRIPT>
  <title></title>
</head>
<BODY>
  <NOSCRIPT>To display this page you need a browser with JavaScript support.</NOSCRIPT>
  <SCRIPT LANGUAGE="JavaScript">
    <!--
      hc_d0("Mv#d|\x3C:,&c@w4YFAtD1 [... and so on, another couple hundreds of characters ...]");
    //-->
  </SCRIPT>
</BODY>
</html>

不用说,像这样的“优化”永远不应该在网络上出现,除非你的目的是降低页面对用户和搜索引擎的可访问性。并且里面的NOSCRIPT标签也让人很不爽,这种东西对某些能阻止javascript的防火墙来说也是不起作用的。馊主意,坏做法!

上面是一个很好的反例,但是还有一些也是应该注意的:

反面教材

1. 去除文档声明

HTML Compresor里面有一个选项——默认是开启的——去除文档声明。我实在想不出这么做会有什么的好处,相反,没有文档类型会激活怪异模式,使页面的布局和行为都出现很严重的问题。文档类型要么放着不动,要么被替换为一个更简短的——HTML5声明。

2.把STRONG用B替代,EM用I替代

还是那个HTML压缩工具里面有一个有害的选项是把元素用比他们更短的“替代品”来替换。问题是B不是STRONG的替代品。I也不是EM的替代品。 STRONG和EM是有语义的——表示强调,而B和I只是去改变字体样式的;他们能改变文字的展现,但是没有任何语义。

虽然浏览器把他们显示成一样的,但是屏幕阅读器和搜索引擎知道他们的区别。

3.去除title,alt属性和label元素。

一条比较重要的原则是如果优化会损失可访问性就不要优化。你可能很想删掉IMG上的“alt”属性,或者链接上的“title”属性,但是节省少量的字节相对于损失的可访问性来说的确是得不偿失。

工具

使“附加优化方法”里面的优化自动化是比较琐碎的事情。已经有一些工具可以去除注释、空格和属性值的引号,但这些工具仍然是比较初级的,它们做的优化还比较有限,我们当然能做得更好:

几个月以前,hakunin 和我都开始做一个很相似的基于Ruby的压缩工具,但都没有完成。

目前来说我们可以用的:

1.Absolute HTML Compressor (桌面程序, windows)

如果你把去除文档类型和用I替换STRONG的选项去掉的话,它做得很不错。

2.HTML Compact (桌面程序, windows)

降低页面的可访问性。应避免使用

3.HTML Compressor (桌面程序, windows)

只是删除空格,甚至把对空格敏感的元素如PRE里面的空格也删除了。用处不大。

4.Pretty Diff (基于网页)

没有选项可以完全的删除空格(只是减少空格)。除了减少空格和并成一行外不做其他的优化,也不能正确处理对空格敏感的元素。用处不大。

5.htmlcompressor (基于java)

这里提到的优化它大部分可以完成(但是不删除选填标签或缩短布尔类型的属性),能正确处理对空格敏感的元素,也许是目前最好的一个选择

可以看到,现在的状况是很令人失望的。好像没有Mac/Linux下的压缩工具,windows下的用处又不大。

将来的考虑

虽然转移或者删减可以(并且应该)在产品成型的时候来处理,但是一团糟的写法压根就不应该出现,不管是成品还是开发阶段,没有任何例外。

最好的优化常常还是人工来处理的:更改页面结构来避免多个元素上重复的class(把它们放到父级元素上去)、去除不是立即要用的内容,将他们动态加载。替换掉不高效的用于展现目的的<br>&nbsp,或替掉换基于表格的布局也是人工优化很好的例子。

就这些优化工具而言,我希望在不久的将来看到更多的压缩工具,将页面体积缩减推向一个新的高度。

如果你知道更多优化HTML的方法,请分享出来。很乐意大家提问,提建议或者纠正我的错误。

本文翻译自Optimizing HTML

Written by admin

February 26th, 2010 at 10:06 pm

this关键字

with 5 comments

javascript最重要的关键字之一是this。但是如果你不了解它的工作原理使用起来就会很困难。

下面我将介绍在事件处理中如何运用它。以后我会增加this的其他用途。

所有者

这篇文章将要讨论的问题是:在函数doSomething()this到底指向谁?

function doSomething() {
   this.style.color = '#cc0000';
}

在javascript中,this始终指向我们正在执行的这个函数的“所有者”,或者更确切地说,函数是哪个对象的方法this就指向哪个对象。当我们在页面中定义函数doSomething()的时候,他的所有者就是这个页面,或者说javascript的window对象(或全局对象)。而一个onclick属性的所有者是它所在的HTML元素。

这种“所属关系”是javascript的面向对象特性造成的,欲了解更多信息请阅读这篇对象亦是关联数组

------------ window --------------------------------------
|                                          / \           |
|                                           |            |
|                                          this          |
|   ----------------                        |            |
|   |   HTML 元素   | <-- this         -----------------  |
|   ----------------      |           | doSomething() |  |
|               |         |           -----------------  |
|          --------------------                          |
|          |   onclick 属性    |                          |
|          --------------------                          |
|                                                        |
----------------------------------------------------------

如果我们直接执行doSomething(),那么this关键字指向window,并且函数会去改变window对象的style.color,由于window对象没有style属性,这个函数会执行失败,并产生js错误。

拷贝

如果我们要合理地运用this就必须确保使用它的函数为正确的HTML元素所拥有,或换一种说法,我们必须把函数拷贝到onclick属性上,传统的事件绑定模型很好地处理了这个问题。

element.onclick = doSomething;

函数被完整地拷贝到了onclick属性上(现在成了一个方法),所以当事件处理函数被执行的时候this指向HTML元素并且它的color会被改变。

------------ window --------------------------------------
|                                                        |
|                                                        |
|                                                        |
|   ----------------                                     |
|   |    HTML元素   | <-- this         -----------------  |
|   ----------------      |           | doSomething() |  |
|               |         |           -----------------  |
|          -----------------------          |            |
|          |doSomething()的一份拷贝|  <--  拷贝函数         |
|          -----------------------                       |
|                                                        |
----------------------------------------------------------

这里有个小技巧是我们可以把函数拷贝到多个事件处理器上,每次this都能指向正确地HTML元素:

------------ window --------------------------------------
|                                                        |
|                                                        |
|                                                        |
|   ----------------                                     |
|   |   HTML元素    | <-- this         -----------------  |
|   ----------------      |           | doSomething() |  |
|               |         |           -----------------  |
|          -----------------------          |            |
|          |doSomething()的一份拷贝|  <--  拷贝函数         |
|          -----------------------          |            |
|                                           |            |
|   -----------------------                 |            |
|   |    另一个HTML元素     | <-- this        |            |
|   -----------------------     |           |            |
|               |               |           |            |
|          -----------------------          |            |
|          |doSomething()的一份拷贝|  <--  拷贝函数         |
|          -----------------------                       |
|                                                        |
----------------------------------------------------------

这样才是比较充分地使用this,每次函数被执行的时候this都指向触发了这个事件的HTML元素,这个HTML元素“拥有”了doSomething()的一份拷贝。

调用

然而如果你使用行内事件绑定方式

<element onclick="doSomething()">

你没有拷贝函数!而是调用了这个函数。其中的区别是很关键的。这里的onclick属性并没有包含任何实际的函数,而只是一个触发了这个函数:

doSomething();

他只是说了句“找到doSomething()并执行它”,当我们找到doSomething()的时候this关键字再一次指向了全局的window对象,并且函数会返回错误提示。

------------ window --------------------------------------
|                                          / \           |
|                                           |            |
|                                          this          |
|   ----------------                        |            |
|   |    HTML元素   | <-- this         -----------------  |
|   ----------------      |           | doSomething() |  |
|               |         |           -----------------  |
|          -----------------------         / \           |
|          | 找到doSomething()    |          |            |
|          | 并执行它             | ----   对函数的调用     |
|          -----------------------                       |
|                                                        |
----------------------------------------------------------

区别

如果你想通过this来获得触发了这个事件的HTML元素,就必须确保this关键字确实被写入到了onclick属性里面,只有这种情况下它才会指向该函数所绑定到的HTML元素。所以如果你测试下面这段

element.onclick = doSomething;
alert(element.onclick)

你将得到:

function doSomething()
{
	this.style.color = '#cc0000';
}

可以看到,this关键字出现在onclick方法里面,因此它会指向HTML元素。

但是如果你测试以下这段:

<element onclick="doSomething()">
alert(element.onclick)

会得到

function onclick()
{
	doSomething()
}

这只是一个对函数doSomething()的调用,this关键字并没有出现在onclick方法里面,所以它不会指向HTML元素。

例子——拷贝

在下面的情况下this会写入onclick方法内:

element.onclick = doSomething
element.addEventListener('click',doSomething,false)
element.onclick = function () {this.style.color = '#cc0000';}
<element onclick="this.style.color = '#cc0000';">

例子——调用

下面这些情况this指向window:

element.onclick = function () {doSomething()}
element.attachEvent('onclick',doSomething)
<element onclick="doSomething()">

注意这里出现了attachEvent()微软事件绑定模型的一个严重的缺点是attachEvent()只建立了对函数的调用但没有拷贝。所以有些时候我们无法知道是哪个HTML元素触发了这个事件。

二者结合

当使用行内事件绑定方式时也可以把this传给函数,使你仍然可以在函数内部使用它:

<element onclick="doSomething(this)">

function doSomething(obj) {
// this出现在了事件处理器内并且传给了函数
// obj现在指向HTML元素,所以你可以做以下操作
obj.style.color = '#cc0000';
}

本文翻译自PPK的The this keyword

Written by admin

January 10th, 2010 at 1:09 am