AngularJS 为什么成功了?

前端

写在前面的话 继上一篇总结之后, 觉得必须补充一下 AngularJS 与 Ionic 的技术性话题 于是, 连夜写了这第一篇. 讲述了 AngularJS 与其他对手之间的优与缺. 我有任何理解错误, 请指正.

AngularJS 的成败

AngularJS 在这两年时光里, 可谓是异军突出. 我们来看看 Google 搜索指数:

如果你可以顺利翻墙的话, 可以看看这个指数链接

(注: 在 v2ex 上面大家有反馈关键字有很大误差, 我试了像 Angular, Ember, 确实有较大的误差, 不过整体趋势仍然比较明显可以表现出来, AngularJS 的指数上升比较明显, 放在这里仅供参考)

现在, 可以说, AngularJS 在前端领域, 已经占据了主要的地位.

虽然它的诞生, 就像 JavaScript 一样带着那样或这样的毛病, 但依然大发光彩.

AngularJS 与 JavaScript, 在我看来, 都属于 2014 年度最佳框架(语言).

我们来详细谈谈它的优点与缺点.

全栈 VS 简单

有人说, AngularJS 太庞大了, 太复杂了, 根本就是发展方向错误. 实则不然, 相反, 我的观点是, 全栈解决方案远大于简单的方案.

既然我对 Rails 很熟悉, 我来举一个 Ruby 界的例子: Rails vs Sinatra. 一个是复杂到 Web 整站解决方案, 既包括了后端, 还包括了前端, 连打包, 压缩, 布署都帮你做好了. 而另一个则是简单到极致, 几行代码就可以写一个 Web 服务. 然而, Sinatra 永远无法打败 Rails, 只能处于小众圈子. 因为只要项目一大, 他们就要重新造一遍 Rails 的轮子.

这个时候, 大部分人需要的是全栈解决方案, 不是小而美的东西.

那么, 显而易见, BackboneJS 与 ReactJS 从这个竞争中出局了.

实际上, AngularJS 像 Rails 一样, 它内部的轮子是可自由替换的, 事实上, 全栈的背后也是以简单作为基础的.

思想的背后

EmberJS 是 AngularJS 强有力的对手, 有很多支持者, EmberJS 的核心实现也是从 Rails 学到了很多东西.

但为什么大家依然选择了 AngularJS, 我以为真正核心的原因只有一点: 一个框架的哲学思想.

貌似有点深奥, 实际上很简单: AngularJS 从一诞生, 就认定了一件事: 在 Web 世界里, 声明式语法要远远好于命令式语法. 从这一点, 就引出了 AngularJS 的主要特性:

  1. 双向数据绑定
  2. 永不操作 DOM

而 EmberJS, 一开始就是 Rails 在前端的实现, 当然很多概念不适用, 并且有些特性又不够, 而现在, 也是补了许多该有的特性, 比如正在开发中的 HTMLBars, View 层无法理解 DOM( HandleBars 只能理解字符串 )是一个硬伤, 这让 AngularJS 优势太明显了: 哲学概念单一, 便于理解. 而 EmberJS, 更像一个后端的思想的框架, 有点水土不服.

或者, 应该换个说法: AngularJS 就像官方想做的那样, 只是想扩展 HTML 语法, 而不得不造了一些概念. 而 EmberJS 则是为了实现而实现. 如果你深入使用, 自会明白我的意思.

易于上手

AngularJS 真的太容易上手了, 当你做过官网上的 Hello World 例子后, 你就会惊讶: 原来不会 JavaScript 也能写好 Web2.0.

而 Ember 则一开始就教你理解各种概念, controller, action, template, router. 等一等, 我们需要一步步向上爬.

但是, 没有银弹

随着前端项目的复杂度上升, jQuery 这种命令式语法已经无法管束整个项目的高质量推进. 但 AngularJS 也不是银弹.

我们俗话有讲: 进入一个世界, 往往会放弃另外的世界. 这放与 AngularJS 身上非常合适: 正是 AngularJS 想把它的哲学思想做到极致, 才会带来诸多新的问题:

  1. 动态作用域问题
  2. 依赖注入问题
  3. digest loop 双向绑定性能问题
  4. directives 不必要的复杂度

这几点, 相信你只要是 AngularJS 深入使用过都会遇到类似问题.

我们看中它的优点, 用它来开发极动感的 AngularJS 前端应用, 也须理解并避开它的缺点.

1. 动态作用域

由于 AngularJS 双向绑定的需要, 你必须给数据指派一个域( scope ), 就像 JavaScript 中的 function, 会将每个不同的域中的数据隔开开来. 但不同的是, JavaScript 或 Java 等拥有完整语言特性的语言, 它们的 scope 的行为是预定义的, 只有有限的几种. 而 scope 则不然, 你无法真正理解它, 就无法理解为什么在 ng-repeat 中修改绑定的值却对应 controller 中的值是无效的一样困惑不解. 但是, 好的是, 当你真正成为程序员时, 你就会豁然开朗.

2. 依赖注入问题

这个问题出现的原因也是由于 AngularJS 的哲学导致: 依赖概念要够简单. 开发者想了一个极取巧的方法: 利用参数的名字作为依赖注入的对象. 正是因为 JavaScript 的强大多变, 他们才能做的到. 然而, 新手们总是发现, 坑来了: 为什么压缩后代码就不能用了? 高手们说: 我们专门做了个轮子, 避免你打包出错. 新手们: 好牛X...

3. 双向绑定的性能问题

双向绑定的目的是大大提高我们开发者的效率, 却因为当今浏览器引擎的"缺陷"( 无法真正理解事件影响范围 ), 而只能采用最笨拙的思路:

只要有事件触发, 就全面执行一次所有的监听( watcher ), 如果监听中有新的值出现, 则再次执行所有的监听, 进行重新计算, 反复最多 10 次.

这里就不解释原理了. 简而易见, 这里可能有性能问题.

但经过测试, 只要绑定对象不超过 2000 次, 则每一次 loop 都不会超出 50 ms. 这个时间差对我们人眼是无感知的.

但我认为, 比起这一点潜在的性能问题( 而且是可以轻松调优的, chrome 下有很好用的插件 ), 我们还是值得去学习应用 AngularJS 的.

4. directives 不必要的复杂度

这个问题是唯一一个从设计上欠考虑的模块了. directives 是一个好东西, 你可以用它来封装各种 HTML 操作, 然后把它们做成组件. 这个特性太酷了.

本来, 一鼓做气, 就可以把 ReactJS 比下去, 可是, 由于设计缺失. 我们只能得到一个半成品:

  1. 语法定义非常蛋疼
  2. scope 在其中非常绕, 难于理解
  3. parser, link 等对于普通开发人员暴露的东西太多, 而难于理解. 而问题是, 对于我们普通开发者而言, 这个 directives 特性是我们必修的.

总结

AngularJS 依然拥有不可比拟的优势, 占据前端开发框架之首也是理所当然. 但 AngularJS 第一代框架确实不够大气, 第二代框架又太超前, 我们也不得不像使用 JavaScript 那样"坑"的语言那样来使用 AngularJS 了. 因为, 我们确实找不到更满意的取代品了.

更为可喜的是, AngularJS 的测试框架设计的极为出色, 这也让它能够不断快速迭代, 也让我们写的应用更为健壮.

这也是我选择一个框架的原因之一.

ps: 我是技术达人李亚飞(微信号), 也欢迎关注我的博客: http://yafeilee.me

发表于 2015.01.13


Bigbang • 2018-02-04 20:12

现在是2018年初,不知道博主对于当初的看法有没有改变?

Bigbang • 2018-02-04 20:12

现在是2018年初,不知道博主对于当初的看法有没有改变?

rocky li • 2015-09-09 09:57

文章太片面,有误导读者嫌疑

fedor • 2015-09-09 09:55

项目小用backbone,大型项目用ReactJS。

Wen • 2015-07-09 13:59

最近在研究Meteor.js, 一个更加全栈的解决方案。不知道楼主有什么看法。

李亚飞 • 2015-01-14 15:45

@老喜

AngularJS 适合应用在复杂的 CRUD 页面, 会不会选它, 就是看它带来的好处能否抵消它的学习成本.
对于技术人员来说, 保持对新技术的学习能力是非常重要的, 这就无关学习曲线的问题了.

老喜 • 2015-01-14 14:38

angularJS 学习曲线呢,感觉很多人还是只停留在表层,深入应用的没那么多。

李亚飞 • 2015-01-13 12:53

hi, 当然可以, 在首页的右侧有订阅入口.

yu kun • 2015-01-13 10:24

你好,可以订阅博客rss吗?