文章目录
  1. 1. 与Angular共事
    1. 1.1. 初始
    2. 1.2. 并肩作战
    3. 1.3. 框架纷争
    4. 1.4. 打怪升级
    5. 1.5. 你好Angular2
  2. 2. 谈谈Angular2
    1. 2.1. 依赖注入
    2. 2.2. 模块化组织
    3. 2.3. 数据绑定
    4. 2.4. 路由和lazyload
    5. 2.5. 编程方式
    6. 2.6. 用AOT进行编译
    7. 2.7. 拥抱变化,迎接未来
    8. 2.8. 参考
  3. 3. 结束语

本文跟随着Angular的变迁聊聊这个框架,分享一些个人的理解。

本骚年刚好是在之前的项目中使用到Angular1,然后现在项目中负责将Angular-beta升级到Angular-release版本。与Angular结识较深,或许也是缘分吧。

与Angular共事


初始

算了算,或许本骚年大概是两年前开始认识Angular,那会backbone.js、underscore.js也还是刚开始流行,而热门的当然还是jQuery、zepto那些吧。
不得不说,当你去仔细理解jQuery的整个设计和架构的时候,才会知道里面的精华和美妙之处。而对jQuery的熟悉也使得我养成了从dom出发的编程思维。

而Angular的出现,则颠覆了大多数jQueryer的思维方式。是的,我们需要从数据和状态开始思考组件,而不是随意地调动dom做想做的事情了。
什么依赖注入(DI)控制器(Controller)指令(Directive)服务(Service)Scope又是什么,为什么还有digest()apply()

很多完全没接触过听说过的概念一拥而入,我没写过JAVA,工程化又是什么?
当时的我,并不知道这些MVC/MVVM框架将对前端产生怎样的一个影响,或者说是带来哥怎样的未来。

然而,就像我开始接触javascript一样,非科班的我没学过其他的语言,所以也不懂得为什么很多人诟病它。
Angular的出现也是一样,从我和它们的初始开始它们就是以这样的形态存在,带来方便的同时也免不了有自己的小缺点,没有对错,没有好坏,只有优势或是不适合的一些场景。

并肩作战

在一遍又一遍去理解Angular中的各种新概念和思维,以及一些业余的尝试之后,我开始把它选为队友,一起战斗。

那时候其实React已经热门起来了,而Vue还没稳定。基于函数式编程的React受到很多人的追捧,而我因为还没去了解熟悉,光从社区和论坛的讨论中无法分辨好坏。

直到产品经理问我,为什么Angular不行呢?
是啊,为什么不行呢?于是乎我把项目从jQuery迁移到Angular上了,准确来说,重构了。

坑是不少,但是越到后面才越发现这次重构的正确性。项目的维护和拓展性能大幅度提升了,于是进入了业务模块快速开拓的阶段。

其实我一直认为,作为一个业务产品,除了性能上的瓶颈,基本上没有框架好坏之分,只有设计架构的人能否正确理解业务和进行抽象架构。

框架纷争

Angular的工程化,一直到现在都会比React/Vue等框架更适合大规模业务的管理吧。尤其是像PC端的管理系统,围绕着简单的增删查改,需要的只是快速拓展业务,而很少复杂的需求和设计。
听过一句话,好的语言设计,能让刚接触的人写出的代码,和牛逼的人写出的代码几乎一样。

函数式编程也好,面向对象也好,其实方式并不是那么重要,我们的最终目标一致的话,其实剩下的更多是相互之间磨合、配合然后高效前进。
React很棒,它的虚拟DOM提升了性能,函数式编程让我们不需要再针对对象设计,我们可以畅快地抽象成一块块功能,然后一层层地封装或者调用。状态这种本不应该维护在函数式编程里面的东西,就让Redux/Flux等抽离出来进行管理吧。
Vue也很不错,它相比React对前端人员友好和易上手,性能也紧跟React,相比Angular要轻量、性能要好。尤其随着移动端的应用场景越来越大,单薄的H5页面很是适合吧。

看看Angular,概念太多上手难,框架太笨重不够灵活,甚至每次的升级都不做向下兼容(Angular1、Angular2-beta、Angular2-release)。
然后我们对Angular的认识停留在这些一般般的风评中,忘记了它的工程化场景更适合大量业务模块的管理,也忽视了它的自我颠覆同时带来了一些很棒的特性(Rxjs和模块化),也不曾注意到现在的它更轻量、更灵活了。

又或者是原Angular1的使用者,看着Angular2的断崖式升级以及beta时期也在不断跳级,望而止步,也没机会深入探视,然后发现灵魂还在,光芒耀眼。

其实框架很多很杂,无法分辨不敢恭维又怎样。每个曾处于浪尖的新事物,必然有它的过人之处,多去了解学习,然后把精髓和优秀的思维带走,把不足记下以防踩坑。
若不去认识认识,怎么会知道这些框架的相似(路由、HTTP、生命周期、模板引擎等)。同样是服务的设计,依赖注入新的服务实例,而使用状态的抽离管理或许需要自行重置状态。

打怪升级

ES6和Webpack的出现,使得很多在Angular1中的设计变得冗余或者稍微落后了。新式特性和语法糖,模块化在Webpack配合Babel的强助攻下破浪而出。
然后Angular推翻重来,出现了Angular2-beta版本。当初宣言不进行Angular1版本的兼容使得它吃了不少亏,毕竟后面还是出了迁移方案的。

我们的项目从Angular1.2升级到1.5+,然后随着浪潮甩掉Grunt和Gulp,调整上了Webpack,同时Angular1.5+的版本已经部分引入了Angular2的一些新的思维(模块化),以及可以尽情使用ES6/ES7的新特性了。
不得不说,像Promise、Module、Class这些API的出现,真的是改变了很多的写码方式和效率。

然后因为项目业务的不断拓展,以及维护人员的增加,团队到后面一致赞同Typescript的引入。事实证明约束的同时也省去了一些不必要的交流,代码的维护性变强了。
这个时候我们的项目状态是,Angular1.5 + Webpack + Typescript,同时因为联调的排期问题我们使用了Angular的mock,真的很实用。

你好Angular2

现在的项目也是相似的,PC端的管理系统。当然它已经换了新马甲,虽然还是beta版本,不过很开心地说:你好呀,Angular2。

控制器(Controller)变成了组件(Component),然后定义都变成了装饰器(@decoretor from es7/typescript)。工厂(factory)没了,服务也要声明可注入(@injectavle)。
然后依赖注入的方式变了,beta版的每次使用分类注入(分directives/providers/pipe注入),然后release版本的模块注入(NgModule的decleration/imports/exports/providers)。
事件绑定((click))和属性绑定([ngClass])的方式变了,定义某类组件都使用了Class,我们看到了this,作用域Scope被藏了起来。

Angular2的beta到release版本也出现了一些大的变动,导致当初的版本已经找不到对应的文档和API了,遇到问题只能翻源码的效率太低了,于是我们升级到release的4.0版本。

Angular-beta到release也有不少的调整吧,具体大家可以参考《从Angular2-beta到Angular4-release框架升级总结》

项目里面也有些调整,上了Angular-cli,它的内核也是webpack。虽然不是很灵活,但在没有很多时间自己实践的情况下还是个不错的选择。然后有了lazyload,有了公用组件模块SharedModule。
团队的小伙伴也说过这么一句话,Angular的项目,基本上拿过来复制粘贴就可以快速相应需求了。

我们的工作很多时候最终目标是一个很棒的产品,无论是体验还是对用户友好。当然免不了地,对自己有些要求的我们也想要一个看起来漂亮的代码和项目架构。
而我个人的习惯一般是,在产品刚启动的时候快速开发,然后规模大了,进行抽象、规范、架构调整,以及多人配合时如何提高开发效率,减少开发和维护成本。

很多人说,你要考虑以后的拓展性,要设计得完美。只是很多时候我们的产品总不能按照想象的顺利发展,我能做的,是和目前项目状况最适合的设计和架构,不多也不少。

谈谈Angular2


依赖注入

Angular的依赖注入可谓是灵魂了,之前有篇详细讲这个的文章《谈谈Angular2中的依赖注入》,这里大致摘录一些。

依赖注入在项目中,体现为项目提供了这样一个注入机制,有人负责提供服务,有人负责消耗服务,而这样的机制提供了中间的接口,并替使用者进行了创建并初始化这样的处理。
我们只需要知道,拿到的是完整可用的服务就好了,至于这个服务内部的实现,甚至是它又依赖了怎样的其他服务,都不需要关注。

其实像我们设计一个项目,自行封装的一些组件和服务,然后再对它们的新建和初始化等等,也经常需要用到依赖注入这种设计方式的。
我们的服务也可以分为有记忆的和无记忆的,关键在于抽象完的组件是否内部记录自身状态,以及怎样维护这个状态等等,甚至设计不合理的话,这样的状态管理会经常使我们感到困扰,所以Redux、Flux和Mobx这样的状态管理框架也就出现了。

而Angular在某种程度上替我们做了这样的工作,并提供我们使用。
在Angular里面我们常常通过服务来共享一些状态的,而这些管理状态和数据的服务,便是通过依赖注入的方式进行处理的。
依赖注入还有有个很棒的地方,就是单元测试很方便,测试的时候也注入需要的服务就好了。

模块化组织

Angular2模块把组件、指令和管道打包成内聚的功能块,每个模块聚焦于一个特性区域、业务领域、工作流或通用工具。
我们不再只是将组件和功能进行模块抽象,也不只是再将一些组件和功能进行再封装,我们还要把这样的功能模块一步步放射到整个应用程序。

这样的模块化思想层层包裹,我们的结构组织也层层地抽象封装,树结构的设计思想从模块组织到依赖注入延伸。
同时,依赖注入使得每个模块,不管层次薄的厚的,都能方便简单地进行状态管理。

Angular2也提供了封装好的一些功能模块,像表单模块FormModule、路由模块RouterModule、Http模块等等。

数据绑定

我们都知道,在Angular中是使用双向绑定的,当然Angular2中调整了分为事件绑定和属性绑定。
这在很多时候都解决了不少的问题,增删查过或者父子通讯最爱用了,换成React/Vue还得手动setState()之类的更新或者通过状态管理工具触发更新。

说脏检查性能太糟,在Angular1中,当数据状态多了一次变更可能导致多次的联动脏检查计算,想想也是挺累的。
脏检查无非是,保存旧的数据,然后和新的数据比较计算,接着更新后再计算,直到没有新的变化为止。

虽然有了很多像React的虚拟DOM,以及Vue的数据跟踪getter和setter,但在Angular2中依然使用脏检查。
不一样的是,添加了zone.js对异步任务进行跟踪,把这个计算放进worker,完了更新回主线程,是个类似多线程的设计,也提升了性能。

在Angular2中应用的组织类似DOM,也是树结构的,脏检查会从根组件开始,自上而下对树上的所有子组件进行检查。
相比Angular1中的带有环的结构,这样的单向数据流效率更高,而且容易预测。

路由和lazyload

路由在Angular-release版本中设计成单独的功能模块,不再跟组件Component有密切的关系。

我没有仔细研究过其他框架的路由模块,不过像lazyload这样的设计也肯定已经考虑进去了吧。
既然这样的话,那这里我拿Angular来说明一下lazyload的闪光之处。

像我们打包页面,很多时候最终生成了一个bundle.js文件。这样,每次当我们请求页面的时候,都请求整个bundle.js并加载,有了Webpack或许我们只需要加载其中的某些模块,但还是需要请求到所有的代码。
很多时候我们或许不需要进入所有的模块,这个时候浪费了很多的资源,同时首屏体验也受到了影响。

通过路由的lazyload以及上面提到的模块化,我们可以把每个lazyload的模块单独打包成一个chunk文件,当进入模块时才请求和加载,当我们的业务规模很大的时候,首屏速度得到大幅度提升。
使用Angular-cli可以很方便地进行路由的lazyload,而若自行使用webpack构建,也只需要加上一个angular-router-loader就好了。

编程方式

Angular2相对Angular1来说,编程方式改变太多。但是如果你熟悉ES6/ES7,就发现Angular2中的很多编程方式都很熟悉。
其实Angular2看起来和Angular1完全是两个框架,很多时候是编程思维习惯导致的。就像当初使用jQuery的我们去学习Angular的感觉,但其实像ES6/ES7的出现这是一个必然的趋势吧。

Typescript的优势也体现在项目的维护性、代码的可读性以及多人配合的沟通效率。它也只是一种方案选择,当然如果有约定好的规范也是很不错的,最终还是看团队的意愿了。
Promise的设计也让代码变得清晰连贯,数据状态的响应处理,同时我们可以方便地进行流式处理和异常处理。
Rxjs的引入可以方便实现事件订阅,有时候可以配合Websocket来进行应用的部分推送更新等功能。
Class的定义方式,配合装饰器Decoretor,可以方便地统一的组件/服务/模块等的创建。

用AOT进行编译

JIT编译导致运行期间的性能损耗。由于需要在浏览器中执行这个编译过程,视图需要花更长时间才能渲染出来。
由于应用包含了Angular编译器以及大量实际上并不需要的库代码,所以文件体积也会更大。更大的应用需要更长的时间进行传输,加载也更慢。
预编译(AOT)会在构建时编译,这样可以在早期截获模板错误,提高应用性能。

事实上只有一个Angular编译器,AOT和JIT之间的差别仅仅在于编译的时机和所用的工具。
使用AOT,编译器仅仅使用一组库在构建期间运行一次;使用JIT,编译器在每个用户的每次运行期间都要用不同的库运行一次。

AOT使得页面渲染更快,无需等待应用首次编译,以及减少体积,提早检测模板错误等等。

拥抱变化,迎接未来

身为框架,Angular和React、Vue各有各的优劣,哪个更适合则跟产品设计、应用场景以及团队等各种因素密切相关,没有谁是最好的,只有当前最适合的一个。
Angular的经常性不兼容,以及1到2的断崖式升级,或许对开发者不大友好。但其实,我很喜欢它的这些改变,干脆利落,自身的缺点由自己去克服。

我们也何尝不是,为何要死守某个框架、某种语言,或是争好坏、分高下。
何尝不抱着开放的心态,拥抱变化,然后迎接未来呢?

参考

结束语


以上只是本人的个人理解,或许存在偏差。世上本就没有十全十美的事物,大家都在努力地相互宽容和理解。
那些我们想要分享的东西,肯定是存在很棒的亮点。而我们要做的,是尽力把自己看到的那完美的一面呈现给大家。

码生艰难,写文不易,给我家猪囤点猫粮了喵~

B站: 被删

查看Github有更多内容噢:https://github.com/godbasin
更欢迎来被删的前端游乐场边撸猫边学前端噢

如果你想要关注日常生活中的我,欢迎关注“牧羊的猪”公众号噢

作者:被删

出处:https://godbasin.github.io

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

文章目录
  1. 1. 与Angular共事
    1. 1.1. 初始
    2. 1.2. 并肩作战
    3. 1.3. 框架纷争
    4. 1.4. 打怪升级
    5. 1.5. 你好Angular2
  2. 2. 谈谈Angular2
    1. 2.1. 依赖注入
    2. 2.2. 模块化组织
    3. 2.3. 数据绑定
    4. 2.4. 路由和lazyload
    5. 2.5. 编程方式
    6. 2.6. 用AOT进行编译
    7. 2.7. 拥抱变化,迎接未来
    8. 2.8. 参考
  3. 3. 结束语