Angular2:从AngularJS 1.x 中学到的经验

小编说:Angular 2 的最终版正式发布,Angular 1 的全平台继任者从此诞生。在上一篇文章中我们讨论了Web 的进化和前端开发的变革对Angular 2诞生的推动,不过不只如此, 1.x中存在的一些缺陷,不值得让我们继续在其中整合强大的工具。

本文选自《迈向Angular 2》,让我们看看Angular2解决了哪些在1.x版本中困扰我们的问题

Controller



AngularJS 1.x 遵从了Model View Controller (MVC)的微架构模式。有人会争论说,它看起来更像 Model View ViewModel (MVVM),因为controller 有自己独立的语法,而视图数据模型是作为scope 或者当前上下文的属性而存在的。但是,如果我们使用Model View Presenter 模式(MVP)也能实现同样的目的。由于可以用各种不同的形式来组织应用逻辑,所以核心团队把AngularJS 1.x 称为Model View Whatever (MVW)框架。

在任何AngularJS 应用程序中,视图(View)都应该是由指令组而成的。各种指令互相协作,从而实现功能完整的用户界面。服务(Service)负责封装应用的业务逻辑。在服务代码中,我们可以通过HTTP 与 RESTful 服务进行通讯,使用WebSocket 甚至使用WebRTC 进行实时通讯。对于我们的应用来说,服务是实现领域模型和业务规则的基础构件。还有另外一个组件就是控制器(Controller),它主要负责处理用户输入并把执行过程代理给对应的服务。

虽然服务和指令都有明确的角色定义,但是在iOS 应用中,我们常常会看到MassiveView Controller 这种反模式。有时候,开发者会尝试在控制器中访问甚至直接修改DOM。一开始的时候,这种方式用来实现一些很简单的功能,例如修改标签的大小,或者快速粗暴地修改标签的样式。另一个值得注意的反模式就是:在不同的控制器中重复实现相同的业务逻辑。开发者倾向于拷贝粘贴这些逻辑,而实际上这些东西应该封装到service 里面去。

构建AngularJS 应用的最佳实践是:控制器根本不应该操作DOM,而是应该把访问和

操作DOM 的逻辑分离到指令中去。如果控制器之间有一些重复的逻辑,最大的可能就是:我们需要把这些逻辑封装到某个服务里面,如果某个控制器需要用到这些功能,就使用AngularJS 的依赖注入机制注入这个服务。

以上就是我们从AngularJS 1.x 中所学习到的内容。这样看来,似乎控制器的功能应该移到指令内部的控制器中去。由于指令支持依赖注入API,所以在接收到用户的输入之后,可以直接把具体的操作代理给注入的服务来执行。基于这一原因,Angular 2 中采用了完全不同的实现方案,删除了ng-controller 指令,解决了滥用该指令导致控制器满天飞的情况。

在《迈向Angular2》第4 章,将会学习如何用Angular 2中的组件和指令来取代AngularJS1.x 中控制器的功能。

Scope



AngularJS 中的数据绑定机制是利用scope 对象来实现的。我们首先在scope 对象上添加各种属性,然后在模板中显式声明需要绑定这些属性(单向绑定或者双向绑定都可以)。这种方案看起来很清晰,但是scope 还有两个更重要的职责:派发事件和实现基于脏值检测的行为。Angular 初学者需要花费大量精力去理解什么是scope 以及怎么使用scope。所以,AngularJS 1.2 引入了一个叫controller as syntax 的概念。它允许我们直接在控制器内部为当前上下文(this)添加属性,而不需要显式注入scope 对象然后再在上面添加属性。以下代码片段示范了这种简化的语法:

Angular 2 更进一步,直接删除了scope 对象。所有表达式都在特定UI 组件的上下文

中执行。把scope API 整体删掉之后使得Angular 2 得到了大幅度简化,我们不再需要显式注入scope 了,只要把属性直接添加到UI 组件上,然后再进行绑定操作即可。这种API 让人感觉更简单也更自然。

在《迈向Angular2》一书第4 章会详细学习组件和脏值检测机制。

依赖注入



在JavaScript 领域,AngularJS 1.x 也许是市面上的第一个通过dependencyinjection (DI)引入inversion of control (IoC)机制的框架。DI 可以带来很多好处,比如:易测试性、更好的代码结构和模块化,以及更简洁明了。虽然在1.x 版本中DI 运行得相当不错,但是Angular 2 对它进行了进一步的发挥。因为 Angular 2 是基于最新web 标准构建的,所以它使用了ECMAScript 2016 装饰器(decorator)语法对使用DI的代码进行了注解。这里的装饰器与Python 中的装饰器或Java 中的注解非常类似。它们都可以使用反射机制来decorate(装饰)指定对象的行为。由于装饰器还没有标准化,也不被主流浏览器所支持,所以使用的时候需要经过中间转换步骤。如果你不想这么麻烦,也可以直接用ECMAScript 5 语法编写一些冗长的代码去实现相同的语义。

新版本的DI 更灵活、功能更丰富,也消除了AngularJS 1.x 中的一些误区,例如API 不统一的问题。在 1.x 中,有些对象是根据参数的位置顺序注入的(例如scope、标签、属性,以及指令link 函数中的控制器);而其他对象则是根据名称注入的(例如在控制器,指令,服务和过滤器中会根据参数名称进行注入)。

在《迈向Angular2》一书第5 章会进一步学习依赖注入API。

服务端渲染



Web 需求越大,web 应用就变得越复杂。构建一个真实的单页应用需要编写大量的JavaScript 代码,把用到的所有外部类库全部一次性包含进来会导致页面上脚本的体积增加到好几兆。在移动设备上初始化应用可能要用几秒到十几秒的时间:从服务端获取所有资源、解析并执行JavaScript、渲染页面、应用所有样式。如果在低端移动设备上使用无线网络,这个过程可能会让用户放弃访问应用。虽然可以用一些技巧来加速这个过程,但是在复杂的应用中,没有银弹。

在尝试提升用户体验的过程中,开发者们发现了所谓的server-side rendering(服务端渲染)技术。它可以把单页应用中所请求的某个视图在服务端渲染好,然后把对应的HTML 直接发送给用户。随后,在所有资源处理完毕之后,脚本就会添加事件监听器并进行数据绑定操作。这样做看起来像是一个提升应用性能的好方法。使用此方法的先驱之一是ReactJS,它利用了Node.js 的DOM 实现在服务端预先渲染用户界面。可惜的是,AngularJS 1.x 的构架不支持这种特性。原因是框架和浏览器API 紧密耦合在一起,在WebWorker 中进行脏值检测的时候我们也遇到过同样的问题。

服务端渲染的另一个典型使用场景就是:构建对Search Engine Optimization(SEO,搜索引擎优化)友好的应用。为了让AngularJS 1.x 应用能够被搜索引擎索引,目前已经出现了很多hack 方法。例如,其中一种实战案例是这么处理的:使用无前端浏览器漫游整个应用,执行每个页面上的脚本并把渲染结果缓存成HTML 文件,从而让搜索引擎能够访问应用。

虽然这种变通方案可以构建对SEO 友好的应用,但是采用服务端渲染技术可以同时解决之前提到的两个问题:一是提升用户体验;二是用更简单优雅的方式来构建对SEO 友好的应用。

只要把Angular 2 和DOM 进行解耦,我们的应用就可以在浏览器之外的环境中运行了。为了实现这一目的,社区已经开发了一款工具,首先在服务端预先渲染单页应用中的视图,然后再转发给浏览器。本书在编写这段内容的时候,这款工具仍然处在开发的早期阶段,所以它并没有被包含在框架的内核中。

在《迈向Angular2》第8 章,我们将会深入学习这款工具。

大规模应用



自从Backbone.js 出现之后 ,MVW 就是构建单页应用的标配。我们可以按照注意点分离原则把业务逻辑从视图中分离出来,从而构建出设计良好的应用。MVM 可以使用观察者模式监听数据模型的改变,当发生改变的时候刷新视图。但是,其中的事件处理器之间存在一些显式或者隐式的依赖,这就使得应用中的数据流不清晰且难以理解。在AngularJS 1.x 中,不同的监视器之间可以相互依赖,从而导致了digest 循环必须进行若干次遍历,这些表达式的结果才能最终趋于稳定。所以,Angular 2 采用了单向数据流设计,优点如下:

  •  更明确的数据流。
  •  不同的数据绑定之间没有依赖关系,所以digest 没有存活时间(TTL)的概念。
  •  性能更高:① digest 循环只运行一次。②创建对immutable/observable (不可变/可观察)数据模型友好的应用程序,从而可以做深度优化。

数据流的改变为AugularJS 1.x 基础构架带来了又一项根本性的变革。

当需要维护一个用JavaScript 编写的庞大的代码库时,我们可能要换一个角度来看数据流的问题。虽然JavaScript 的鸭子类型(指js 对象的动态特性——译者注)让这门语言非常灵活,但是同时也让IDE 和文本编辑器很难对代码进行分析和支持。对大型项目进行代码重构变得很难而且容易出错,原因是在大多数情况下进行静态分析和类型推断是不可能的。同时,在缺少编译器的情况下,很容易出现错别字,在跑测试用例或者真正运行应用之前很难发现这些错误。

Angular 核心团队决定使用TypeScript ,因为它有更好的工具,还有编译时类型检查;使用TypeScript 有助于提升生产效率,还能减少出错。如上图所述,TypeScript是ECMAScript 的超集,它引入了显式类型注解和编译器。TypeScript 代码会被编译成当前浏览器所支持的普通的JavaScript。TypeScript 从1.6 版开始,已经实现了ECMAScript 2016 装饰器,它是Angular 2 的完美选择。

各种IDE 和文本编辑器都可以更好地对TypeScript 进行静态代码分析和类型检查。所有这些优点都可以减少出错的概率,从而极大地提升生产率,同时还可以简化代码重构过程。TypeScript 另一个重要的隐含优点是使用静态类型带来的性能提升,因为JavaScript 虚拟机可以对静态类型进行运行时优化。

在在《迈向Angular2》第3 章中我们将详细讨论TypeScript。

模板



模板是AngularJS 1.x 的核心特性之一。模板是简单的HTML 并且不需要中间的处理和编译过程,这一点与mustache 之类的大多数模板引擎不同。AngularJS 中的模板简洁而强大,我们可以在模板内部创建Domain Specific Language(DSL,领域建模语言)来扩展HTML,还可以使用自定义标签和属性。

当然,这也是Web Component 背后的主要目标之一。前面我们已经提到过Angular 2是怎么使用这一新技术的以及为什么要使用它的原因。尽管AngularJS 1.x 中的模板很强大,但是还有很大的改进空间!Angular 2 中的模版吸取了上一个版本中的精华,解决了一些让人困惑的问题,增强了模板的功能。

假设我们创建了一个指令,允许用户通过标签的attribute 给它传递一个成员属性。在AngularJS 1.x 中,有以下三种不同的实现方法:

如果我们有一个user 指令,然后需要给它传递name 属性,有三种不同的方法可以实现(这里的意思看起来和上一段的末尾有一点重复,原文如此——译者注):第一种方法是传递一个字面量(在这个例子里面,也就是"literal");第二种方法是传递一个字符串,这个字符串可以当成表达式来执行(在这个例子里面,也就是"expression");第三种方法是在{{}}中传递一个表达式。应该使用哪一种语法完全由指令的具体实现来决定,这就使得指令的API 变成一团乱麻并且难以记忆。

在日常工作中,处理大量基于不同的设计方案而开发的组件是一件令人沮丧的事情。为了解决这些问题,我们需要引入一种通用的约定。但是,为了取得良好的结果并保持API 的一致性,需要整个社区达成一致。

Angular 2 为属性提供了特殊的语法来解决这个问题,属性值会在当前组件的上下文中执行,同时为传递字面量提供了不同的语法。

根据从AngularJS 1.x 中获得的经验,还有一件事情我们已经习惯了,那就是模板指令里面使用的微语法(microsyntax ),如ng-if、nf-for。举个例子,在 AngularJS1.x 中,如果需要遍历一个用户列表并展示用户姓名,我们可以这样做:

虽然这种语法看起来很直观,但是只有有限的工具能支持它。所以,Angular 2 引入了更明确的语法来解决这个问题,同时语义上也更丰富:

以上代码明确定义了一个(user)属性,这个属性将会在迭代(users)的上下文中创建。

但是,这种语法在输入的时候显得太冗长。所以,开发者可以使用以下简化语法,然后再编译成更冗长的形式:

文本编辑器和IDE 可以为改进型的新模板提供更高级的工具支持。在《迈向Angular2》第4 章Angular 2 中的组件和指令中,我们会讨论Angular 2 中的模板。

脏值检测



在关于WebWorker 的小节中,我们已经提到过:在WebWorker 实例化出来的其他线程上下文中运行digest 循环的时机。利用JavaScript 虚拟机的代码优化机制可以获得显著的性能提升,其中一种优化叫做内联缓存。但是AngularJS 1.x 中实现的digest循环内存使用效率不高,而且阻碍了这种优化过程。Angular 团队在这方面做了许多的研究,发现了提升digest 循环性能和效率的各种方法。这些发现推动了全新的脏值检测机制的开发。

为了获得更大的灵活性,Angular 团队把脏值检测机制提取了出来,并且与框架内核进行了解耦。这样一来就可以开发出不同的脏值检测策略,在不同的环境中可以采用不同的策略。

最终结果就是:Angular 2 中有两种内置脏值检测机制:

  • 动态脏值检测:与AngularJS 1.x 中的脏值检测机制类似。用于不允许eval()的系统中,如CSP 插件和Chrome 插件。
  • JIT 脏值检测:运行时动态生成脏值检测代码,允许 JavaScript 虚拟机进行深度代码优化。

《迈向Angular2》第4 章,会学习到新的脏值检测机制以及它们的配置方法。

到此,我们讨论了为什么需要使用最新版的JavaScript 语言;为什么要使用Web Component 和WebWorker;以及为什么不值得在1.x 版本中整合所有这些强大的工具。新框架层出不穷,好不好用只有自己踩过坑才会知道。

时间: 2024-10-29 01:37:01

Angular2:从AngularJS 1.x 中学到的经验的相关文章

《构建实时机器学习系统》一1.7 案例:Netflix在机器学习竞赛中学到的经验

1.7 案例:Netflix在机器学习竞赛中学到的经验 美国领先的付费视频公司 Netflix 在机器学习.系统推荐方面都做出了卓越的贡献, 早在 2007 年,Netflix 就率先提出了百万美元大奖,奖励在 Netflix Prize 竞赛中优胜的队伍.Netflix Prize通过为期三年的竞赛,积累了机器学习宝贵的第一手资料,成为了机器学习中的经典案例,这里我们介绍以下两个方面. 1.7.1 Netflix 用户信息被逆向工程 Netflix Prize进行影片推荐预测时,使用的数据包括

聊聊从设计实战失败案例中学到的经验教训

  今天这篇文章不长,但非常值得初入设计的同学阅读,如果经常抱怨甲方不懂设计,每次改稿都愤慨不已,那就更有必要学习了,来自一个设计师的失败案例总结,用亲历经验告诉你,为什么优秀的设计师很少提视觉,而都把解决问题挂嘴边. 修习手艺是一门磨性子的活儿,设计也不例外.历经提案怎么改都通不过的愤慨,不如心平气和来看待它,会发现这其实是不可多得的学习机会.再恶俗的反馈,深究其中,也会有所得.设计不是纯艺术,自High不该是我们的追求.设计是一种解决问题的方式,所不同的是,它用眼睛来说话. 虽然"解决方案&

Angular 2:Web技术发展的必然选择

小编说:中秋之际(9月15日),谷歌正式发布了 Angular 2 的最终版,成为Angular 1 的全平台继任者. 在Angular 2 剧烈变更以及缺乏向下兼容性的背后,主要的推动力是web 技术的演进以及来自于AngularJS 1.x 的经验教训.本文节选自<迈向Angular 2>一书,此书基于对Angular 2架构和设计方面的深入理解,带你快速转入Angular 2的全新世界,降低Angular 2学习曲线. 在本文中,我们将着重讨论为何Web 的进化和前端开发的变革会促使An

angular2使用简单介绍_AngularJS

让我们从零开始,使用Typescript构建一个超级简单的 AngularJs 2应用. 先跑一个DEMO 运行这个 DEMO先来感受一下 AngularJS2 的应用. 下面是这个应用的文件结构 angular2-app |_ app | |_ app.component.ts | |_ main.ts |_ index.html |_ license.md 总结来说就是一个 index.html 文件和两个在 app 文件下的 Typescript 文件, 我们可以hold住! 下面我们将一

详解Angular2中的编程对象Observable_AngularJS

前言 RxJs提供的核心是Observable对象,它是一个使用可观察数据序列实现组合异步和事件编程. 跟这个很类似的异步编程模型是Promise,Promise是基于状态变化的异步模型,一旦由等待状态进入成功或失败状态便不能再次修改,当状态变化时订阅者只能够拿到一个值:而Observable是基于序列的异步编程模型,随着序列的变化,订阅者可以持续不断的获取新的值.而且Promise只提供回话机制,并没有更多的操作来支持对结果的复杂处理,而Observable提供了多种多样的操作符,来处理运算结

站长们:我该选择继续做站还是向生活低头

做站一年了,从去年暑假接触网站,到今天8月16日整整一周年,总想写些什么,今天终于触动键盘了.一年多来摸爬滚打,在网络上风风雨雨,不断在网络的道路上摸索,可以说做的站多不胜数,而成功的网站却没有一个.开始做站的时候还在大学校园,现在走出了大学校门,面临的是生活的压力,到底是向生活低头,还是继续坚持自己的爱好和追求,一直处于迷茫和挣扎的心理状态.如果选择生活,那就意味着要放弃自己的追求:如果选择继续做站,那么谁来为我的生活买单?在迷茫中我选择了两者的中和,打工与做站结合起来,我希望打工能暂时解决我

保持网站简洁外观:简洁的网页设计衬托网站内容

文章描述:通过本文你能从中学到一些经验.本文作者迈克·埃文斯(Michael Evans)是一位热情的博客写手.他擅长Photoshop,贡献了多篇网页设计和开发的教程,并且受到了读者们的喜爱. 导语:简洁并不等于极简主义,在保持网站简洁的外观的同时,辅以其它元素的使用,同样能够达到要求.那如何做到这一点呢?通过本文你能从中学到一些经验.本文作者迈克·埃文斯(Michael Evans)是一位热情的博客写手.他擅长Photoshop,贡献了多篇网页设计和开发的教程,并且受到了读者们的喜爱. 洁净

10 个项目文档最佳实践

在软件开发和维护过程中,文档是必不可少的资料,它可以提高软件开发的效率,保证软件的质量,而且在软件的使用过程中有指导.帮助.解惑的作用.尤其在维护工作中,文档的重要性更是不言而喻.  本文整理了软件开发中10个最佳的文档编写实践,希望能对你的工作有所帮助.  1.  将编写文档作为开发工作中的一个重要环节(例如,占用总开发时间的10%).在软件开发中,不能没有文档,但如果编写文档占用了大部分的时间也不合适.可以根据需要制定代码文档.需求说明文档.设计文档.测试文档.用户手册等,在制定完成后,可以

网站更改关键词之后的运营方法

我做网站大约有两年的时间了,一直都是兼职做的,说不上有多大的成就,但也有一点小小的收获吧,目前个人兼职经营了四个网站,今天只是想给大家分享一下我的网站改行的经验,目前情况还不错,希望大家能从中学到一点经验,也希望有不同意见的可以给我提出来,以便我的改进,谢谢了. 我以前定位的时间选的是一个故事的网站,关键词定位的是爱情故事,域名是爱情天空的拼音和英文字母这个域名不说太好吧,因为太长了,但是也是比较好记的,所以大家申请域名的时间一定要注意.关键词我选好了,于是就冲冲的上线了,网站运营了半年之久,流