转载

从 StackOverflow 看 Angular 1.x

去年 IE Team 把 issue tracker 放到 StackOverflow 之后,我一度以为 SO 会革了 MSDN Library 和 Forum 的命(也就是让我丢掉饭碗),就像 GitHub 干掉 Codeplex 和 Google Code 一样。刚好当时我学习和实践 AngularJS 有一段时间了,我就想到 SO 上试试身手,看看自己的水平,是否能够帮助到别人。

于是我每天大概花半个小时不到在 SO 的 Angular JS tag 下面解答问题。玩了半个月左右,拿到一千多分。在 SO 上刷分当然不是目的,但是分数比较好的体现了你回答的问题的准确度和热门度,所以我比较关注这个指标,但这个过程只能用艰难来形容。之所以称之为艰难,主要原因有两个。

  1. 如果题目比较基础,解答相对容易。但是你会遇到很多三哥朋友们第一时间冲出来回答。甚至很多时候,你已经做出解答了,他们还源源不断地 post 和你一模一样的 answer 。
  2. 如果题目比较深入,确实没有三哥和你抢了,但很多时候这也意味着,没有多少人会关注这个问题,为你的答案点赞。

这两个现象其实都来源于一个 root cause :基础的问题,回答起来更容易,花的时间更少,得到的分数更多。而这样的问题,受到所有人的喜爱。为什么呢?对于抢分狂魔而言,这种题目分数更好得;对于热心答题不计较分数的好心人而言,回答这种问题,能够把时间省下来帮助更多的人,何乐而不为?当整个社区都呈现这种状态是,你就不难得到当年老赵对 SO 的评论: 如果你经过深思熟虑也无法解决的问题,丢到 SO 上,也基本上不会得到你想要的答案 。这是个悲伤的结论,但 it’s true 。

SO 其实也意识到这个问题了我估计,于是他们搞了个 Golden Badge 叫做 Unsung Hero 。获得这个 Badge 的条件是,你超过一半的答案被选为正确答案,但是没人给你 upvote(也就意味着关注度小)。真的是名副其实,无名英雄。最开始拿到这个 Badge 的时候,我并没有特别高兴。但当我得到上面的结论时,我就释然了。高兴了无聊了工作累了,我就爬上去回答一些我知道的问题。

这几天突然看到自己又一次上了 AngularJS 这个 Tag 的 Last 30 days top answerers ,我想,既然在 SO 上最热门最抢手的问题都是比较基础的、简单的,这也间接说明,对于新手而言,这些知识点具备一定学习曲线,并没有那么容易上手和熟悉。如果把这些知识点和问题做一个整理,这一定是一个不错的文档,也能从中看出这个语言或框架在设计方面的不足。于是我从前到后阅读了一遍我回答过的 Angular 的问题,很快发现不少反复出现或者同类型的提问。

下面让我们一起,从我的角度,看看大家学习 Angular 1.x 的时候通常会遇到哪些困难。

一:Angular Principles

第一类问题是关于 Angular 的运行原理。像 ASP.NET 这种框架,你大部分时候都不需要理解它的机制,而当你不得不去理解 ASP.NET 是怎么运行,那基本说明你遇到了非常坑爹的问题了。但是 Angular 并不是这样的,即使你是上手才半个礼拜的新手,当你需要完成一些特定的功能,你就不得不理解 Angular 的 principles,否则你就会掉入坑中爬不出来。这也就是业界对 Angular 最大的批评,学习曲线比较高。

Digest Loop

这是我心目中的 Angular 第一大杀手。很多前端工程师从纯 JS 或者别的框架迁移到 Angular 的时候,最经常问的就是,为什么我更新了某某 object 的值,页面上没有更新呢? Angular 使用 Digest cycle 来实现 two way binding,而他们的操作并没有进入到这个 cycle 中,比如 ace update text , show json , image change 。 GitHub 上有这样一群 repo ,他们专门负责把第三方的 library 进行包装,使得能够在 Angular 中使用。老实讲, Angular 养活了一批人呢。等2.0上市了,大家又要一股脑儿把这些 library 重新包装,有兴趣的同学不妨试试,是个不错的学习 Angular 和 Contribute to Open Source 的机会。

还有就是在写 directive 的时候,更新了 model 却不能 刷新 页面

好不容易 developer 知道可以使用 $apply $digest 去手动 trigger digest loop,他们也会经常遇到 infinite digest cycle 的问题,简直要疯了。

Expressions

Angular 中有你可以这么使用expression

  1. 在 built-in 的 directive 中,比如 <input type="text" name="userName" ng-model="user.name"
  2. 另一种就是使用 double bracket <p>My first expression: {{ value }}</p>

可是奇怪的事情,当你使用 ng-src 的时候,你需要这样写 <img ng-src="http://www.gravatar.com/avatar/{{hash}}" alt="Description"/> … 我已经不知道该说什么好了 …你可以再看看这里 1 , 2 。

$scope

很多人搞不对expression也可能是因为没有理解 scope 。scope 既是连接 controller 和 view 的胶水,也是 expression 的运行环境。很多朋友在这里栽了,带来的结果往往是搞不定 data binding 。

Module definition

如果你只是通过官方的demo来学习Angular,你可能会搞不清楚 angular.module('app', [])angular.module('app') 的区别,并且由于调用的错误,导致 module 不断地被反复 initialize 。

Angular config/run phase

在 module 的 bootstrap 过程中,你可以通过指定自定义的 Configuration blocks 来操作 provider/constants,或者使用 Run blocks 来配置 instances/constants ,千万不要 错用了 。

DI

一般 dependency injection 出现问题,基本都是用户粗心 漏掉了某个 factory ,或者是使用了 minification 。

二:Directive

什么是 directive ,这里我只简单贴一下官方的说法

At a high level, directives are markers on a DOM element (such as an attribute, element name, comment or CSS class) that tell AngularJS’s HTML compiler ($compile) to attach a specified behavior to that DOM element or even transform the DOM element and its children.

directive 能够很好滴帮助实现模块化,在 Angular 在自己的实现过程中,就把不少功能以 directive 的方式提供给开发者。用户也可以自己书写 directive 对功能进行抽象。在我看来,directive 往往是初学者比较难以掌握的。

Built-in Directives

首先是 Angular 提供的 directive 。有的时候,即使是认真研习文档,你也不一定能够成功理解它们的运行机制,很多朋友在这里就吃了苦头了。印象里 built-in directive 这个方面我拿分相对容易,因为我比较勤劳,如果文档不能够帮助解决问题的话,我会直接跑去看源码。如果问我泡 StackOverflow 最大的收获是什么,那一定是读了不少 Angular 的 source code。

SO 上经常会提及的 built-in directive 有

  1. ng-disabled
  2. ng-change
  3. ng-repeat , ng-repeat-start/ng-repeat-end 。尤其是后者,满多人上来问,我该怎么用 ng-repeat 实现 xxx 功能,基本都是因为他们不知道 ng-repeat-start/end .
  4. ng-cloak 玩过 Angular 的同学都知道,如果页面 loading 比较慢,就会看到页面上充满着各种花括号,然后才会变成相应的文字。为了解决这种问题, Angular 给我们提供了 ng-cloak (ng-bind也能实现一样的效果)。这是我给 microsoft.github.io 交的第一个 pr :)
  5. ng - style / ng-class 在使用 JQuery 的时候,可以直接操作 DOM 来添加样式,但这并不是 Angular 推荐的方式。很多人意识到了这点,他们只是刚好没听说 ngStyle/ngClass 。

Write your own directive

除了使用 built-in 的 directive ,Angular 也鼓励大家来写自己的 directive。但是这里大家经常会遇到 model binding 或者是如何给 attr 传值 ,再或者从 directive 中 访问 controller 的 scope 。

三:$http

$http 只是一个 built-in 的 service ,但我要把它单独拿出来讲一讲,一方面是因为这是一个非常基础的 service (访问后台 Rest API ),另一方面是 developer 在和 $http 总会不约而同的想静静。

  1. Encoding 真的是所有程序员的噩梦。到底是 form 还是 json 还是 byte array ?如何设置 header ?如何配置 callback ? 问题 多 多 。
  2. Cache 为了减少 call 后台的 cost,$http 提供了 cache 的功能 。
  3. Headers 论如何为所有的 $http request 配置 header 。
  4. JSONP
  5. CORS. Angular 把 rendering engine 搬到了浏览器里,我们需要通过 ajax 向 backend server 抓取数据然后在页面上渲染,这就不可避免的遇到了 cross domain 的各种 failure ,算得上前端届又一个 老 大 难 问题 。
  6. Promise. ASP.NET 有 async/wait,你猜 Angular 里面 都 有 啥 。
  7. interceptor. Angular 允许你 customize $http 的 error handling 。

最后,读者朋友如何跑到我博客首页看一看,你还能看到去年我对 Angular 的吐槽 Angular 一个值得当心的bug 。是的,我喷的就是 $http ,虽然没有什么卵用。

四:Best Practice

还有一类问题,来自有理想有追求的朋友。他们想知道如何 think in Angular,如何操作能够有比较好的 performance等等。

Communication/Data Sharing between Controllers/Factories

当你想在不同的 context 之间共享 data 的时候,全局变量堪称 fast and dirty 。但不幸的是,从你上大学的第一天开始,就有人不断告诉你这么做是不负责任滴。于是为了避免被同事 code review 的时候 challenge,不断有人来问该 如何 在 controller/factory/directive/etc 之间 share data 。俗称,月经帖。

Model binding/Performance Enhancement

其实这个和上文提到的digest loop可以放在一起谈。Angular 使用了 dirty check 去实现 two-way binding,也就是很傻瓜地反复地遍历 watch list,看看大家有没有什么更新。当页面上的绑定的 element 开始增多(大概2000+),dirty check 就会严重拖累整个页面的 performance。

dirty check 简直是 Angular 1.x 的阿克琉斯之踵,然后谷歌的大大们在2.0中,把它无情地抛下了。听闻这个消息,我等屁民“弹冠相庆”,谁让它 老是 折磨 我们 呢。

去年四月我第一次接触 Angular,写了点自嗨的小玩具,转眼已经过去十三月了。短短的一年光阴,Angular 1.x 已经确立了不可撼动的一哥地位,而2.0 也已经“洗心革面”马上要出来重新做人。至于我,在尝试完各种姿势之后,也算是找到了一点方向。希望2015年剩下的时间里,做好一个产品,来一点 breaking change。

Breaking Change!! Hell Yeah!!

正文到此结束
Loading...