我以前写过一篇说说我对moo、prototype、JQuery的看法在我的blogjava博客里面(现在我已经不更新了,完全使用这个wordpress的博客)。今天也是在Google Reader里面看到JavaEye的另外一个朋友lifesinger的一篇文章:大胆预测下几个JS框架的走势,我个人不是非常同意,所以写了如下回复,也发在我的blog吧。
完全不同意lifesinger的说法:
1、JQuery会走的比较远。因为Django会走的比较远。而且JQuery的内部设计很好,如果说它不好估计是没有理解它的核心理念。而且John Resig的确是个勤奋的福音传播者,它的js使用理念很好,所以这个库会随着它的plugins库的数量质量的双重提高,占重要位置。同时浏览器效率的的提高也会给它注上强心剂。
2、YUI的api设计不好。作为oo的库它不好,作为fp的库它更不好,所以它不会有多好。不过在widget类库里面它肯定继续占重要地位,因为YUI的widget的确兼容性很好。
3、moo我很喜欢,但是它的演化保持了小众的特点,小步前进,api设计上比较偏设计师的想法。做大型项目的时候你回发现moo没有对如何组织你的项目给很好的“风格”上的建议,所以它也就会在大型项目上哑火。
4、Ext,我看没什么大的希望了。因为它的授权问题,基本上它已经不在是开源社区友好的(它也许可以做自由软件社区友好吧)。而且作为一个UI Widget库,它并没有把可访问性放在重要的地方来重视,所以随着UI的可访问性要求的上升,它的默认皮肤带来的eyecandy估计就没法盖过usability的缺失了。
你没有提到Prototype,它目前还是js lib的第一名,随着活跃的RoR社区的继续推进,它应该还会持续足够的市场份额。而且它和JQuery同属于有强烈“风格”的库,所以即使项目很大,它还可以保证代码的可读性与可维护性,这对于很多项目来说是至关重要的。
关于dojo我不说了,以前说过:说说我对moo、prototype、JQuery的看法的回复里面有。
Sep
关于javascript库的一个回复
Aug
关于Javascript的入门图书
犀牛书绝对的过时,也绝对的不友好。在开始的时候,作为一本系统讲解javascript的书,它非常注重阐述规范,所以在那个时代它是最好的图书。但是现在,作为js技术的入门图书,我们有一些更好的从javascript的精髓和基本理念入手的图书,读完他们你就可以体会到规范为什么是这个样子,从记忆角度来说理解后的记忆要强过死记硬背,所以用这些图书入门是更好的选择。
Update: 有位Sina的同事说道犀牛书还是要有一本的,目的是作为参考书。我倒是觉得这个完全可以依靠网络,因为大部分时候我们就是想索引一下方法,或者看看方法签名和解释,这个时候通过在线服务绝对要好过翻书。服务里面gotapi是个不错的选择!
在国内看翻译的推荐看:
1、大辫子nicholas写的Javascript高级程序设计。
2、John Resig写的精通Javascript (Pro javascript)
ppk on javascript这本书也不错,比较实用,但是个人感觉没有精通Javascriptt这本讲的清楚。
如果看原文可以期待:
1、John Resig的Javascript Ninja,未出版,但是有样章。
How Closures Work
Using (function(){})()
Instantiation and Prototypes
Class-like Code
2、Js大神Douglas Crockford的Javascript The good parts.
上周和钱钱讨论Programming Ruby这本书的时候我们也持这个观点,它曾经是一本非常棒的入门书,因为那个时候它是第一本非日文的Ruby图书。但是这本经典书到了现在已经有了很多不一样的竞争者,像钱钱同学推荐的Every day scripting with ruby就更偏实践,更容易让你入ruby的门。
Jul
短小精悍的Javascript模板引擎
今天看到Jonh Resig的博客里面提到了他在他的Secrets of the JavaScript Ninja这本书里面介绍的一种简单的模板,代码如下:
// Simple JavaScript Templating
// John Resig - http://ejohn.org/ - MIT Licensed
(function(){
var cache = {};
this.tmpl = function tmpl(str, data){
// Figure out if we’re getting a template, or if we need to
// load the template - and be sure to [...]
项目中的JsUnit是使用ant脚本运行的,里面需要设置BROWSER_PATH的环境变量来启动浏览器。在本地check in代码的时候,我们会运行一下测试来减少愚蠢错误被提交到代码控制系统。但是在我的mac下Firefox只能启动一个实例,在运行JsUnit test的时候会提醒我已经打开了Firefox,不能打开另外一个实例,这样我必须关闭正在运行的Firefox。而且由于我比较喜欢打开非常多的Tabs来保持浏览状态,所以关闭Firefox让我很不爽,再说,因为重新启动的Firefox里面带了很多的Tabs,所以经常造成实际运行的JsUnit test发生随机性的超时错误,这个就不能容忍了,因为这无法保证我们的信心。
那么,为什么FF不能启动多个实例呢?原因是它们共享同一个Firefox的profile,所以没法多个实例并发访问。但是通过命令行参数是可以创建多个profile给firefox的,简单了。不过遇到的问题是JsUnit的ant任务会检测BROWSER_PATH是否存在,所以如果我把带参数的命令行写到环境变量里面Ant无法检测到这个文件就会报错。那么如果关闭检测可以么?还是不行。因为JsUnit的StandaloneTest里面实际最后会调用DefaultProcessStarter的execute方法,这个方法调用Runtime.getRuntime().exec(command),这个实现非常直接,不过因为parameters如果直接写到命令行里会发生文件无法找到的问题(应该用数组将命令和参数传入)所以没有办法传入,还是无法运行。
放弃hack吧,我可以修改Ant task和JsUnit的方法,但是绝对不好,因为这个hack没有提交回去的意义。
所以换个思路,这样做:我们去写个shell来解决它。
先在终端运行/Applications/Firefox.app/Contents/MacOS/firefox-bin -CreateProfile jsunit,这时候会弹出窗口让你确认创建这个profile,选择一下不使用extensions和各种工具条,这样减少这些设置对测试的不良影响。
然后在你的home目录创建一个firefox.sh,里面写上:
/Applications/Firefox.app/Contents/MacOS/firefox-bin -P jsunit $1
前提是你的Mac使用的是默认的bash,否则修改$1为对应的引用字符。然后chmod firefox.sh 555,让它可以运行。
下面就是修改你的~/.profile:
export BROWSER_PATH=/Users/[User path]/firefox.sh
source ~/.profile让修改生效再运行JsUnit就OK啦。如法炮制想开几个Firefox实例都可以啦。同样方法也适用于让Firefox2和Firefox3共同运行!非常简单。还可以做到开发和浏览分开……以此类推。
回顾一下JsUnit的代码写的不好,如果像Selenium一样能够自动创建一个profile就好了,因为那样可以减少测试之间的影响,还可以让Selenium并行执行。我想,如果有空我可以做一下这个工作:D
这是一篇很好的讲前端页面优化的slide,当然有不少内容我们都看过很多遍了,我以前做过的:
Performance and Scalability of Ajax Part 1
Performance and Scalability of Ajax Part 2
里面的内容也有一些重复。不过这次我还是很有收获,比如IBM的Page detailer就是个不错的profiler工具。还有使用document.getElementsByTagName(’*’).length简单判断dom复杂度的方法也是不错的。结果是:
新浪首页是3109
财经首页是4260
新浪邮箱是169
纸条箱251
sohu是2k4
netease是1k4
很有意思。
结绳记事。
| View | Upload your own
对于javascript来说,通过单元测试,你也可以实现TDD。对你非常有好处,一是减少了js变动带来的代码退化问题,另外一方面是TDD可以改变你设计程序的方式。
举个简单的例子,写javascript很多情况下是和BOM(也就是文档模型)和DOM打交道的,这样可以说javascript程序很容易与dom高度耦合,这样的程序运行起来没有问题,但是应对需求变化的能力会比较地。但是根据人的思维方式,javascript很多时候是先出页面,然后根据页面逐渐调试着写出javascript,对于开发者来说,脑子里并不是真正的清楚自己要什么,而是在想界面的结果……这样产生的高耦合代码不容易测试,也难以面对多变的界面。
所以,换一种方式思考。如果用单元测试的方式去写,你就需要考虑程序的可测试性,这会细化你的程序的模块粒度,因为细粒度的抽象容易单元测试。同时由于js单元测试的页面是mock出来的,所以一般都会尽量的简单,这样会减少程序远对界面的依赖。同时由于界面的可测是性问题,也许会减少对element的style的修改,转而使用语义话的css。例如如果一个元素高亮,你可以element.style['font-size']=’bold’;element.style.color=’red’l….,当然你也可以element.addClassName(’highlight’),然后那些不好验证的界面的约束条件可以放到css里面去,放给可用性和用户验收测试去验证。这样的单元测试的验证条件(assertion)会简单很多,如果写过单元测试的朋友肯定会有感触的。
那么,常见的Javascript的单元测试框架有JsUnit和scrit.aculo.us的单元测试框架两个。前者方便用ant调用和分析结果,适合使用了ant的项目。而后者的优点就是界面好看,直接运行产生的报告清楚漂亮。所以小型项目我倾向后者,而大型项目我倾向前者。当然,由于js的动态特性,其实做个单元测试框架非常简单,所以自己动手也无妨。关键是要写,而且争取做到测试先行。
前面是个引子,其实写这个的原因是今天上午的一个郁闷的事。
前面的blog entry说道我升级了Firefox3,结果遇到了getElementsByClassName问题。但是今天换到另外一个项目组,没有用那个方法,程序也正常。可是我TDD的写一个新的feature的时候却发现可爱的JsUnit的testRunner在Firefox3里面无法工作,从firebug里面看到了一堆安全性问题。估计是firefox3的新安全模型造成的吧。那么,由于firefox3覆盖了firefox2,所以难道我没法写程序了?当然不可以,还有safari嘛。马上开始去写测试了,写好测试执行测试,发现红条。嗯,很满意,因为TDD的红-绿-红-绿的节奏就是这样的。然后我开始去写实现来满足这个测试……结果忙活了一上午就是不行……而且发现一些原来的测试也无法通过了……我仔细寻找问题,diff修改的内容,可是最后实在没有发现任何让它不能通过的原因,因为手工在firebug里面都已经验证了写的实现是没有问题的呀……崩溃。此时我突然想起来我们的持续集成服务器里面没有跑safari的JsUnit测试……也就是说不能确定在safari下全绿(此时的背景是我们的持续集成显示全部绿色,也就是说所有的测试都可以同过,包括windows和linux平台还有IE及Firefox),那么我可能衰了。马上开动camino(靠,一上午都忘记用它执行JsUnit了,因为我的习惯是Camino里面保存to read list),运行一下全绿。很兴奋,但是感觉刚才寻找问题的1个多小时被无辜的浪费了,心疼呀。
那么,请注意啦,我只是想提醒,jsUnit可能不能在safari下正常工作(大部分测试没有问题,少量在其它浏览器正常的测试在safari下无法工作),我用的是safari3.0.4……
Firefox3解决了一些内存泄露问题,或者说主要的是解决了一些长时间运行以后的内存占用问题。由于使用mac的习惯是休眠不关机,所还是在正式版出来之前选择了升级到firefox beta2。
那么作为开发人员肯定遇到firebug不能用的问题,还好,我们可以用firebug的beta版本来解决这个问题,当然这个firebug还是会出现莫名其妙的问题,无所谓啦,不久就会发布正式版本了。
这些都是废话,问题集中在firefox beta2提供了原生的getElementsByClassName方法,而我们大家都很愿意使用的prototype库正巧也给Element封装过getElementsByClassName方法,看起来两者的作用是一样的,但是不巧……其实两者还是有很大差别的,所以造成了如果你的项目正巧用了getElementsByClassName方法,而后你又用习惯的prototype方式便利了它……那么你的程序就不能在Firefox3 beta2工作了……
我们以前的习惯就是不用考虑新浏览器的javascript兼容行问题,只需要考虑向后兼容,但是这次问题还是出现了变化。
其实原因是简单的:
1、Firefox3实现的原生getElementsByClassName方法返回的不是javascript数组(Array),而是html element collection,这个东西可以用标准的方式遍历,但是却与Array没有共同的prototype(这个指javascript里面的原型继承的prototype)。所以,很不幸,如果你用了Prototype库的那个返回Array的方法写程序,然后使用了Array增强方法里面的first()等方法或者Emmerable里面的each()等方法,那么程序一定会出错。此时你可以$A一下这个html element collection,但是这不是好方法。因为其实Prototype在1.6以后就不推荐使用getElementsByClassName方法了。
2、那么解决的方法就是使用select方法代替原来的getElementsByClassName方法,不过记得要给参数的前面加个”.”。比如oneElement.getElementsByClassName(’someClass’)应该修改为oneElement.select(’.someClass’)。而其实select方法由于接受css selector语法,可以实现更强大的选择操作。
嗯,非常废话。
那么简单的说:如果你在Firefox3里面发现你的基于Prototype库的js程序的getElementsByClassName以后出现了method null的错误,那么你需要用select方法代替它。且考虑到长时间的不兼容状态,最好完全消除你的程序中的getElementsByClassName同名方法调用,不关你用什么js库。