你很喜欢Gmail和Trello之类的单页面应用,可是不太肯定该从何开始。也许你的JavaScript代码是如此的杂乱无章,以至于你很想在下一个项目上尝试下JavaScript MVC库和框架,却苦于没有头绪?我正在撰写一本单页面应用的书,因此我阅读了大量网上的相关资料。在这里我尝试提供一些见解,但愿能够帮助你下决定。javascript
这里讨论的是时下最热的框架,AngularJS、Backbone、Ember和Knockout。同时提到了Batman、CANjs、Meteor和Spine,可是没有详细展开。html
咱们从多个不一样的角度考察每一个项目,包括社区、领导、成熟度、大小、依赖、互操做性、启发、理念和特性。前端
社区是一个衡量任何开源项目健康程度的重要指数。如下表格显示了GitHub上每一个项目的关注者数量。java
你固然不应仅仅根据这些数据作决定,可是它们确实为你提供了关于这些框架的一些感性认识:web
最主流:ajax
正在高速成长的:数据库
关注总量较低可是增加迅猛的:编程
特别值得注意的是AngularJS 13个月以来的惊人增加(379%)。在你作决定的时候要考虑上这一点。下面的图表比较了13个月以来GitHub关注者的增加速度,能够看出某个项目的社区成长的速度。考虑到原先的社区大小,Meteor(130%)、Ember(104%)、Knockout(76%)和Backbone(64%)的增加速度也很惊人。json
了解项目的核心开发者的背景,他们建立框架时尝试解决的问题,有助于你欣赏他们在设计上的决策和动机。例如,David Heinemeier Hansson,流行的Ruby on Rails框架的缔造者,是37signals的签约开发者,从事项目设计,每周只有10小时能花在开发框架上。Ruby on Rails事实上是从他和37signals的签约工做中提取出来的。这一背景有助于你理解为何这个框架须要将开发效率提高到极限——这意味这使用大量的约定(已经作出的决定)和支架程序(生成的代码)。下面,我将介绍JavaScript MVC 框架的缔造者,也许也能激起你对他们的工做的欣赏。segmentfault
Jeremy Ashkenas和DocumentCloud
Jeremy Ashkenas是CoffeeScript编程语言、Backbone.js JavaScript框架和Underscore.js JavaScript工具库的创立者。根据维基百科,他如今在NYTimes/DocumentCloud从事互动新闻方面的开发。
图片来自The Canadian University Software Engineering Conference。
AngularJS最初由Google的Miško Hevery和Adam Abrons于2009年开发,当时是一个在线JSON存储服务的一部分。Abrons后来离开了这个项目,可是在Google工做的Hevery继续开发,和Google的员工Igor Minár、Vojta Jína一块儿维护这个库。
图片来自Devoxx 2012
Steve Sanderson是Knockout的原做者。Steve Sanderson如今为微软工做,他所在的团队开发ASP.NET、IIS和其余web项目。他之前之外包开发者或顾问身份为Bristol周边的客户开发.NET下的软件,他还为Apress写了一些书,包括《Pro ASP.NET MVC框架》。
Ember核心成员中最知名的公众人物是Yehuda Katz和Tom Dale。
Yehuda Katz是Ember.js、Ruby on Rails和jQuery的核心开发者,他白天的时间花在他创办的创业公司,Tilde Inc.。Yehuda是畅销书《jQuery in Action》和《Rails 3 in Action》的做者之一。
Tom Dale原先在SproutCore团队工做。他之前是苹果软件工程师,在开发MobileMe和iCloud应用时精通了前端JavaScript技能。
图片来自Ember Team
Meteor的开发团队刚刚获得了1.12千万美金,因此他们能够全职开发。他们的团队有12名开发者,每一个开发者的简历都让人印象深入。这个团队拥有雄心勃勃的计划,超越了大多数专一于组织客户端代码和状态的JavaScript MVC框架。Meteor是一个全端框架,包括服务器架构和数据库。
评估框架的成熟度能够帮助你理解在项目中使用新技术的风险。未经考验的新框架在文档、扩展性、稳定性(API改变)和支持(寻找了解该框架的开发者来维护代码)方面可能存在问题,这些问题可能致使出乎意料的结果,即便从其余方面看起来决策很明智。须要考虑的项目包括:多少生产环境下的应用使用这些框架?这些应用有多少用户?文档是否良好?例子和教程是否充足?例子是否过期?API是否稳定?其余开发者了解或正打算了解这门技术么?
了解每一个框架的大小,它会在你的应用中增长多少份量是很重要的。大小会影响性能,不过它同时也会暗示你这个框架的雄心有多大,你学习它可能须要花多少时间,以及它提供多少帮助你构建应用的方式(即特性和鲁棒性)。一个框架的野心越大,特性越多,一般也就意味更难在应用的页面上将它与其余部件组合。轻量的框架更像一个库,将他集成到你的项目中所耗费的精力也相对较小。
包括Backbone和Spine在内的一些项目为本身的轻量而自豪,这些项目更多地将本身视做库,而不是框架。一般这些小型的框架留下了空间,你可使用你本身的库来实现特定功能,例如模板和路由。我在讨论这些框架的特性的时候将继续讨论这个话题。
包括Ember和AngularJS在内的其余项目雄心勃勃,更适合叫作框架。它们一般拥有更多内建的特性,更少依赖外部库。
下面的列表显示了我更倾向于将哪些项目纳入库或框架:
库 | 框架 |
---|---|
Backbone | Ember |
Knockout | AngularJS |
Spine | Batman |
CanJS | Meteor |
使用这些项目构建真实世界的应用的时候还须要哪些库?如下的图表展现了为了保证开发效率每一个库所需的依赖,以及这些依赖的大小。
经过从cdnjs下载库,咱们收集了这些数据。在实践中,大多数的项目会使用jQuery配合这些框架处理DOM,由于须要动画和AJAX。在移动应用中,使用Zepto.js来代替jQuery处理DOM不是什么稀奇的事。Zepto.js是一个比jQuery轻量得多的库。虽然Zepto.js不支持Internet Explorer,可是移动应用一般不须要为此操心。AngularJS包含了一个jQuery 的缩减版jQLite。可是若是你在项目中使用了jQuery的话,它会被覆盖。AngularJS团队鼓励开发者,如非必要,不要添加完整的jQuery库。为了帮助你作出正确的选择,下面的表格同时显示了移动版(假定使用Zepto.js)和web版(假定使用jQuery)。
这一部分讨论是否框架设计为控制整个页面或者它能够被用于现存页面的一个部分——你可能想渐渐将新技术引入现有的项目。前面的库和框架的讨论基本能够体现每一个项目的互操做性,库更倾向于很容易地集成到现存的项目,而框架为你作更多的事,可是不容易和其余项目配合。
AngularJS能够和其余库很好地配合,可是它鼓励开发者们考虑是否能够不用jQuery和jQueryUI.事实上Angular内置了一个jQuery的子集jqLite。遵循这一实践的理由是让单元测试更容易,由于不少依赖库和插件设计的时候没有考虑单元测试,相应地更难和单元测试配合。在实践中,大多数的开发者最终仍是由于某些特性使用了jQuery.
因为Backbone的小尺寸和无预设的架构,将其包含在众多流行的客户端库和服务器端技术中很容易。
被设计为在运行时控制整个页面,因此不太适合用于页面的部分。
能够在项目中做为小组件使用,不控制整个页面。
记者采访音乐家时最爱问的问题是“你在成长的时候听哪些艺术家的音乐,或者说,谁启发了你?”这个问题经常使得读者可以预期音乐家的声乐。这些框架中大部分的观念都不是全新的,而是来自于创造者之前工做的项目中喜欢的部分。这一部分总结了我从框架创造者的访谈中收集到的关于启发的信息。
HTML类的声明性的语言,Adobe和Flex、微软的WPF\Silverligt等RIA技术给AngularJS的影响很深。这些声明性技术没有”主体“方法,仅仅表达须要发生什么,而不指定具体实现。视图和模型中的数据双向绑定是这一声明式编程风格在绝佳例子。此外,在Google的服务器端Java代码中大量使用的依赖注入和IOC容器(特别是Juice)也启发了AngularJS的创造者。他们重视单元测试,须要框架被设计容许依赖注入,这样测试就能够从其余应用层剥离出来,运行起来也会更快。
Tom Dale在Quora上谈了Ember受到的影响:
Ember.js刚开始开发的时候,咱们从Cocoa等本地应用程序框架引入一些概念,不事后来咱们以为这些概念弊大于利,或者说它们和Web应用程序格格不入。所以,咱们开始从Ruby on Rails和Backbone.js 等开源项目中寻找灵感。所以,Ember.js结合了本地应用的强大和现代web的轻量。
此外,Ember.js是SproutCore JavaScript库的进化版,SproutCore中止仿效Cocoa而更多地借鉴jQuery的时候,Ember诞生了,理解这一点很重要。
hanselminutes的播客提供了Steve Sanderson受到哪些方面启发的背景信息。总结一下,MVVM设计模式和微软的WPF、Sliverlight等声明性技术是最大的启发者。你可能会发现Knockout的最佳特性——声明性的数据双向绑定——和Anjular类似,由于二者的启发者是类似的。
报纸在报道新闻的时候努力保持中立。惟一的例外是编者案,鼓励表达观点,做者一般在问题上占据一个强烈的立场。可是大多数状况,这二者既不是严格的中立报道,也不是强烈的意见表达,而是位于二者之间的连续统。技术框架也有相似的划分,便是否强主张。例如,Ruby on Rails推崇约定优于配置,而且为开发者作了大量决定,包括文件结构和数据访问。相应地,它被认为是强主张的。其余Sinatra类的服务器端框架更轻量,并不预设文件结构和数据访问。相应的,被当作是无主张的。服务端框架有理念,客户端JavaScript MVC框架一样有,咱们讨论的框架也能够被置于强主张和无主张的连续统中考察。让咱们看看每一个项目,而后讨论他们的理念。
Backbone是最开明的框架,极度无主张,容许开发者作出本身的决定,有时这会致使代码差别过大而难以维护。惟一的例外是Backbone假定服务器端有一个REST服务,我会在特性部分详细讨论这一点。这一假定能够经过覆盖模型的sync方法来绕过。
AngularJS有较强的主张,特别是它强调可测试性和依赖注入。此外,HTML类的声明性编程很棒的理念也在框架中普遍体现。
Ember力求开发者仅对应用的特有部分做决定,其他所有交给约定和支架。这个理念和Ruby on Rails和jQuery很接近。这一理念最好的表达出如今emberjs.com的网站上:
不要浪费时间作那些可有可无的选择。Ember.js吸纳了常见的惯用法,所以你能够专一于应用的特殊部分,而不是从新发明轮子。
Ember标准化了文件和url结构,固然,有必要的时候也容许你覆盖这些设定。你能够预期的是大量的代码会为你生成,大量的相似文件结构的约定。相应地,你须要作出的常规选择更少,由于框架已经为你选定了合理的默认值,你能够着手构建你的应用的特殊部分。
路由和数据存储留给开发者决定。不预设文件或URL结构。甚至容许用基于字符串的模板替换声明性的基于DOM的模板。
咱们能够将这些JavaScript MVC框架当作是帮助开发者构建单页应用的经常使用特性集合。每一个框架实现这些特性的方式,或者不实现这些特性的方式(经过其余库来补全框架的功能)是值得留心的。
除此之外,一些框架提供经常使用的语言层面的服务,例如通用的pub/sub事件模型和面向对象的继承支持。
这是最受吹捧的特性。你经过HTML input修改了数据,绑定到input的JavaScript对象立刻更新,其余绑定的用户接口元素也随之更新。在不少框架中,反之亦然。若是你修改了JavaScript对象,html会自动刷新。这是一个web上的双向的数据绑定,咱们在Flex、Windows Forms、WPF等富客户端应用框架中见过这类绑定。如下的表格显示了哪些框架支持数据绑定。
有些人可能持有异议,由于Backbone和Spine部分支持数据绑定。可是我以为大量工做须要留给开发者,保险起见,不如说这些库不支持这些特性。
客户端的JavaScript数据模型须要穿插在HTML中,这些框架采用两种方式解决问题。
基于字符串的模板(目前最流行的是handlebars.js),将字符串、文本模板中的动态部分替换为模型中的数据。字符串常被提到也饱受争议的特性之一是性能。其缺点是调试控制语句类的逻辑很困难。
基于DOM的模板拥抱标记语言的声明式本性,这是开了挂的html,经过html中的附加属性来描述须要的绑定和事件。这些库须要的代码大大减小,为开发者作了不少事情。
一些框架(Backbone、Spine)更专一于模型,要求开发者在base模型的基础上扩展JavaScript类,经过.get()
和.set()
访问属性,这样就能跟踪改动,模型的变更也会触发事件。KnockoutJS让开发者在原始的JavaScript对象上应用可察封装,而后经过object.propertyName()
访问属性(当心,别丢了括号)。
其余库(AngularJS)对页面上的全部绑定的DOM元素做脏检查,由于没有标准的get和set访问器。所以将这些库用于大页面时将致使性能问题。这些库不只须要更少的刷新模板的代码,也不须要你使用特定的get和set访问器来修改模型中的数据,因此你可使用原始的JavaScript对象。这大大提高了开发效率,这一点在框架的初学者身上体现得尤其明显。
这些框架经过如下方式将数据存储到服务器
一些框架默认预设后端有很是整洁的REST JSON服务,而且,至少在默认的状况下,前端与后端频繁交互,在后台异步更新数据,而用户界面响应流畅。这些框架内部使用jQuery或Zepto发送合适的AJAX请求给服务器。用户界面的HTML DOM元素监听应用的JavaScript对象模型的改动,同步机制获得模型属性的更改提醒,将改动发送给REST服务,确保模型和服务器同步。
Backbone默认在客户端保存数据以前发送请求,这样服务器端和客户端同步就很容易。和Backbone很是相似的Spine框架,采用了不一样的方式,在异步发送请求到服务器前,先在客户端存储记录,这提供了更好的用户界面响应,在移动应用中常发生的离线状态下也能工做。若是你的项目须要支持离线,须要了解清楚框架对该特性的支持
这些框架要求开发者使用$.ajax
(jQuery)来调用服务,或者添加兼容的开源库处理数据存储需求。
Meteor之类精心制做的框架拥有更完整的数据存储方案,可是要求服务器端有MongoDB数据库。这类方案试图提供一个扩展性优异的默认解决方案,提供从头至尾的JavaScript开发体验。
如下的表格总结了每一个框架是如何处理数据存储的。
将URL路由映射到JavaScript函数,能够支持浏览器的后退按钮。单页应用最大的缺点之一是因为页面无刷新,浏览器历史不会添加条目,因此后退按钮一般没法将用户带回页面的前一状态,除非开发者在主要的状态改变时作一些额外的工做,经过在URL后附加井号,或者,使用现代浏览器的push和pop状态,实现状态跟踪机制。总之,大多数项目都提供基本、初步而有用的功能。Knockout的作法很简单,容许你使用其余的第三方开源库。
考察各个框架的特性以后,我发现我并非在作一个“苹果对苹果”的比较。一个更为公平的比较也许是将AngularJS和EmberJS之类全面的框架与配合第三方库使用的Backbone和KnockoutJS之类的MV*框架进行比较。具体来讲,下面的比较会更有意义:
之后的博客中我会继续深刻。
为项目选择JavaScript MVC框架时有大量须要考虑的事项,我但愿本文是一个良好的开始。请在评论中分享你使用这些框架的体验,包括它们的优异之处,也包括它们使用上的陷阱。