破pure

pure是我用过的最差的前端框架:1. 布局不兼容老版flex-box,大量Android手机用不了;2. 外层框架字间距缩小,还得单独恢复;3. .pure-button里一堆莫名其妙的属性,用Android手机自带的WebKit无法正常tap。小是小,没带来啥价值,毛病又多,所以我一直不喜欢雅虎系的东西。

soma.js, infuse.js, Nervenet

分析与Nervenet比较相似的框架:soma.js与其的差异,介绍Nervenet中有哪些比较独到的地方。

上一篇日志中,我介绍了Nervenet的创作思路。虽然JavaScript有着各种各样的先天不足,但是,运气也是实力的一部分,所以广大开发者只有用各种手法去适应它、改良它。应该说大家干得很棒,我也想贡献自己的力量,于是创造了Nervenet,希望解决我在开发中遇到的各种问题。

就在我写完Nervenet初版的时候,偶然看到MVC框架soma.js的介绍,发现跟我的思路很相像(其中用到的IoC类库:infuse.js,也是他们开发的)。于是仔细研究了一番,学到不少东西。今天我准便拿Nervenet和它们分析对比一下。

soma.js

我自认是个不喜欢“重复发明轮子”的人,于是看到出发点和实现方式如此接近的框架,不免一惊,心说果然世界足够大,持同样想法的人非常多。不知道soma.js的作者有没有用过robotlegs,二者的API真的很像(也许是mvc框架的标配吧,我没看过相关介绍)。我最初也希望引入robotlegs的做法来改善JavaScript编程体验,不过在反复思考后,觉得并不需要全部移植,比如mediator。在Flash里,新的影片剪辑被添加到舞台上时会触发Event.ADDED事件,可以被robotlegs侦听;同时,所有mc都是Sprite的子类,可以使用类名作为索引来创建需要的mediator。而到了JavaScript方面,Dom节点发生变化并不会触发事件;添加的Dom节点也没有类的关系,所以这里的mediator只能我们自行创建,这样其实也就没什么实质性的好处了。

另一个不太需要移植的是Command类。在MVC框架中,它的功能基本就是响应全局事件,进行相应的处理,很多时候只要实现execute方法就好。ActionScript 3在面向方向上做的比较充分,代码都会封装成类,于是Command里还可以放一些helper类型的函数;到了JavaScript这儿就显得不太合适了,既没有强继承关系也没有类型检查,甚至连类的实现都不完整,helper也可以用闭包实现,如果一样搞成类来处理,只是凭空加重了对代码的限制,在我看来有点得不偿失了。

所以我在Nervenet中并没有把robotlegs的功能都移植,而是选取部分比较重要一定会用的实现了。(代码参看测试用例,这里不贴了)

infuse.js

接着再说infuse.js。我一开始准备直接给对象加上app或者context或者injector属性,但是一直觉得这样太过简单粗暴;看过源码发现他们比我略微温柔一点,先遍历对象的属性,如果map了同名属性,就注入进去——仔细想想这差不多是另一种粗暴吧,不由分说的注入同名属性,如果代码不是针对infuse.js写的,可能会产生更多问题。不过我还是学习了这种做法,并进行了一些改造:如果对象属性中有以“$”(可配置)开头的同名属性,就注入。有了这样的规则,新写代码有理可依,改动代码也会比较放心,阅读代码时也有利于识别本身属性和注入属性。

JavaScript没有类型检查,但是在日常开发中难免遇到多个类的实例适合同一个名字,比如model、remote之类的,如果在注入时能自动选择合适的类型,那自然是极好的。于是我想到利用变量声明时的初始值,把类名包括命名空间写进去,作为类型说明,就可以在注入时自动选择合适的类型了。

代码请看测试用例inject部分。

值得一提的是,infuse.js中每个函数都对参数进行了充分的验证,很值得学习,不过我目前还是偷懒只验证了很少一部分。

依赖管理和代码加载

依赖管理和代码加载也是我力图实现的功能,虽然看起来和架构无关,不过在操作层面上,还是比较合拍的。因为我们总要有一个入口函数,比如jQuery中的$(function () {});,通过分析入口函数,就能得到依赖关系,继而可以实现依赖管理和代码加载,这样丝毫不会影响代码架构。目前我也正是这么做的。

不过这种“自然”的代码书写方式也会给加载带来难度。无论AMD还是CMD,都会把代码以函数的形式封装起来,在依赖处理完成后执行;而这种自然的方式,就要求每段代码执行前依赖都已经加载了,所以只能用Ajax把代码以文本的形式加载下来,分析依赖,继续加载,直至全部完成;在按照依赖关系放入script标签执行。如此一来,执行的代码是不允许依赖关系嵌套的,那么,以闭包来实现私有属性和方法的做法就行不通了。这点我还在思考解决方案。

使用方式参看测试用例

总结

目前Nervenet已经初步完成,我正在编写入门文档,并将其应用到实际项目中进行测试。这些完成后将发布0.1版。目前市面上有一些做法很接近的框架,不过具体实现上还有差异,孰优孰劣也有待验证。我会尽量解决各种开发中的痛点。

HTML5梦工厂交流会

今天参加HTML5梦工厂交流会的记录。

在微博上看到 @HTML5梦工厂 要开一个小型的交流会, @司徒正美 要来分享他的Avalon框架,我算了算,今天正好没事儿,就报名参加了。

自从在宠物派见识到架构给产品开发带来的提升后,我就开始关注各种框架,并且在加入点乐后开始使用Backbone。Backbone是个很好的框架,解决了很多JavaScript的先天不足;当然还有一些地方可以加强,这也是我最近在努力的地方。与Backbone所属的MVC不同,Avalon是一个MVVM框架,与近期开始流行的Angular、Ember.js使用了同一个模式。所以我一直想多了解下这个模式的特点。

不得不说,正美大的普通话和音量有点影响效果。听下来,我的理解是这样:

  1. MVVM = Model + View + ViewModel
  2. 在前端开发方面,HTML + CSS承担了View的职责,所以我们只需要实现Model + ViewModel部分就可以了
  3. Model是数据结构,属于设计方面的工作,所以职责集中在ViewModel的实现
  4. ViewModel等同于业务逻辑
  5. Web开发使用MVVM的优势在于,我们可以只关注业务逻辑,也就是ViewModel的实现,这样就极大减少工作量和代码量

不过我还是有一些疑问,比如性能、复用性、维护效率之类的。看来有必要用Angular框架做一个项目了(大厂产品应该更有保障些~)。

会上还听了一个CodeJam项目《谁是卧底》的分享,坦白说那哥们对phonegap开发最佳实践的理解还不如我,有机会写篇文章。

最后帮公司打了个广告,希望能收几份简历。回头Nervenet能拿出去见人的时候也去分享下吧。

前端框架点评

点评一下当下各种前端框架、类库。

前两天被人@,提问前端框架的问题。这还是第一次在微博上被陌生人提问,感觉有点小激动。今天写篇小文章,简单点评一下我用过的前端框架,希望对大家有所帮助。

本文涉及的范围

本文要点评的前端框架,都是我用过的,以JavaScript框架为主,也可能包括一些工具类库。由于前端的特殊性,弱语言HTML和CSS是必不可少的工具,运行机制导致很多成熟的工程学方法没法用,必须用工具库补充。烦请大家不要抠字眼,我一向很马虎,呵呵。

Bootstrap

一定要先推荐Bootstrap。它由Twitter的两位工程师首创,当前版本2.3.1,涵盖了文本、布局、表单、工具,除了暂时没有日期选择器之外,几乎包含了网页所需的一切。我们知道,网页出现是为了传递信息,而成熟的印刷业对其影响很大,表现出来就是,HTML中很多标签,比如H1~H6p等,都是有具体语义的。但很多前端框架并未给予他们足够的重视,所以往往需要我们重置或者自己动手写。Bootstrap则不是这样。它不仅包含大量组件,还帮助我们给每种可能用到的语义标签都定义了样式,又设计出很多helper;而其网格系统也能帮我们出色完成排版工作。总而言之,使用它几乎足以满足任何网页开发需求。

值得一提的是,Bootstrap的组件和Widget都基于HTML标签构建,非常好用;而响应用户操作则基于对document的侦听,所以几乎不会对我们其它代码逻辑造成影响,我们可以放心大胆的在项目当中使用。当然,Bootstrap依赖jQuery,后者近期遭遇到一些纷争。不过我还是要强烈推荐这个框架。

jQuery UI

比较遗憾的是,虽然号称UI,但jQuery UI只能算作一个组件库。因为缺少基础排版支持,所以既想使用jQuery UI,又想和自己的样式保持一致会有些困难,需要花费不少时间做修改。

抛开这一点,jQuery UI也是个很好的工具,几个widget都很实用,文档丰富详实,如果项目本身对交互要求不高,只是个别地方需要一些功能补充,jQuery UI确实是不错的选择。尤其当我们需要draggablesortableresizable这几个功能时,选择的余地真的不大。

HTML5 Boilerplate

这个工具力图给开发者提供一个舒适的起点。他们为项目建立了标准化的目录结构,并且把常用的资源都整理在合适的位置,这样我们只需要替换它们就能保证项目对所有浏览器都有完美表现。同时,他们重置了CSS,引入了GA统计,在页面中标记了合适的输入点,这样我们能尽快投入到项目逻辑的开发中。

但这个工具的问题也很明显,它努力达成的目标,是消弭浏览期差异。假如我们只需要统一的环境就能开展工作,那H5B就足够了;而实际上,我们通常需要更多,比如排版、比如组件。所以,这个工具对我来说,学习的意义大于使用的意义。

HTML KickStart

我见过的前端框架里只有这个跟Bootstrap的覆盖面接近。它的设计更好,更鲜艳更有活力,不过最近的开发好像慢了下来。我并没有真正使用它,因为它的组件太少了。

Backbone

非常好的MV*框架,真的像根脊柱一样,把被jQuery拆的七零八散的js统一在合理的框架内,让整个项目都变得协调了。引入Collection真的很天才,结合其出色的View设计——其实Backbone的View并不是传统意义上的View,更像mediator——可以看出,Backbone的设计者对Web开发有着深刻理解。哦,差点忘了,Router还能帮我们很好的整理单页应用的逻辑。

不过js毕竟是一门很烂的语言——或者让我换种表述方式,缺陷很多,所以它尚无法做到像AS3的Robotlegs那样好。不过,如果我们希望把代码组织的更好,Backbone类的框架是不可或缺的。

Rachet

Rachet的目的和架构,很像Bootstrap,不过它瞄准在移动端。Rachet现在仍处于比较低级的阶段,组件太少,开发起来不太方便,最多相当于Kickstart把。可惜的是,移动端移动框架普遍较弱,在我看来,基于它的Junior仍然是不二之选。

Zepto

说到移动端开发就不能不提Zepto。它力图实现一个十分类似jQuery的库,不过只考虑支持移动端,所以体积会小很多,速度也会快不少。Zepto的升级频率最近也不高,不过还是到了1.0。新版Zepto放弃了ruby,使用coffee作为编译工具,支持使用者自由组合功能模块,相当贴心。

不过具体使用时,还是会有一些函数的用法和jQuery不同,需要注意。举个例子,css函数,jQuery里支持数字,比如$('div').css('height', 100),会把页面中所有div的高度设置为100px;而Zepto不行,必须$('div').css('height', '100px')才会正常工作。

jQuery Mobile

强大的jQuery团队最失败的作品。贪恋于风光的过去,迷信“全覆盖”,使得jQuery Mobile步履蹒跚,在移动平台上无法取得足够好的性能表现(早期版本甚至不支持固定底部)。而这直接带来了对HTML在移动端的质疑。有很多本不擅长前端开发的人,看到Phonegap,就直接上jQuery Mobile,结果发现性能不行,体验很差,便在各种渠道大放厥词,说HTML不行。这种行为直接伤害了HTML和Hybrid应用。

jQuery Mobile失败不仅在于此。jQuery本身方便快捷,使用它很容易养成不重视代码组织的习惯;而在移动端,单页应用占据主流,这意味着,使用jQuery Mobile很可能无法良好的组织代码,直接带来项目维护成本的提高。另外,早期版本的设计也不可避免的带有大量Web痕迹,导致实用性不足。所以直到今天,jQuery Mobile都还是个悲剧。

不过,jQuery 2.0已经beta2了,我们知道,jQuery 2.0里放弃了对IE678的支持,性能会得到不小的提升;jQuery Mobile 1.3已经引入了对hash的支持,组织代码好多了;同时,随着3次小版本更新,越来越多适用于移动应用的组件加入进来,大大扩充了军备库。我认为,未来的jQuery Mobile,值得一试。

Sencha Touch

大家可能还记得,Facebook闹过一阵,说HTML5不够好,还把他们的手机客户端用原生重做了一遍。之后Sencha的两位工程师表示不服,以HTML5为基础开发了功能几乎完全一样的客户端,他们用到的框架就是Sencha Touch。据说,它的性能比jQuery Mobile好不少。

但是,真正用了就知道,sencha touch实在太不“前端”了。它里面几乎没有给HTML和CSS留下太多位置,明明十分强力的布局样式工具,被封装成了单薄的接口;但是没少往JS框架里加内容。结果就是用起来非常复杂,随时需要看文档;自定义困难,它里面甚至有一个属性叫“html”,用来填入大段文本类型的html;数级嵌套起来的对象也很让人头疼,而且感觉维护也不会太容易。所以我做了一半就还是放弃了。劝大家也别去尝试了。

如果有哪位高人愿意以实际经验教育我的,我洗耳恭听。