第二章 Angular应用程序剖析
图2-1 Shopping cart with discount
前面例子会正确的执行, 但是这里有一个潜在的性能问题. 虽然并不明显, 如果你在totalCart()
中设置一个调试断点, 你会发现在渲染页面时它被调用了6次. 虽然在这个应用程序中你从来没有注意到它, 但是在更多复杂的应用程序中, 运行它6次可能是一个问题.
为什么是6次? 其中3次我们可以很轻易的跟踪到, 因为它分别在下面三个过程中运行一次:
{{totalCart() | currency}}
模板中subtotal()
函数中$watch()
函数中然后是Angular再运行它们一次, 因而带给我们6次运行. Angular这样做是为了验证在你的模型中变化是否完全传播出去以及验证你的模型是否稳定. Angular通过检查一份所监控属性的副本与它们当前值比较来确认它们是否改变. 事实上, Angular也可以运行它多达十次来确保是否完全传播开. 如果发生这种情况, 你可能需要依赖循环来修复它.
虽然你现在会担心这个问题, 但是当你阅读完本书时它可能就不再是问题了. 然而Angular不得不在JavaScript中实现数据绑定, 我们一直与TC39的人共同努力实现一个底层的原生的Object.observe()
. 一旦有了它, Angular将自动使用Object.observe()
随时随地呈现给你一个原生效率的数据绑定.
译注:?TC39
在下一章中你会看到, Angular有一个很好的Chrome调试扩展程序(Chrome插件)Batarang, 它将自动给你突出(高亮)昂贵的数据绑定(从性能的角度而言, 表示数据绑定的方式并不是较好的方式).
译注:
Batarang?- 这是一个Angular调试与性能监控工具.Batarang-Github
现在我们知道了这个问题, 这里有一些方法可以解决它. 一种方式是在items数组变化时创建$watch
并且只重新计$scope
的total, discount和subtotal属性值.
做到这一点, 我们只需要使用这些属性更新模板:
图2-2 Shop items
作为服务本身可以有依赖关系, Module API允许你在的依赖中定义依赖关系.
在大多数应用程序中, 创建一个单一的模块将所有的代码放入其中并将所有的依赖也放在里面足以很好的工作. 如果你使用来自第三方库的服务或者指令, 它们自带有其自身的模块. 由于你的应用程序依赖它们, 你可以引用它们作为你的应用程序的依赖.
举个例子, 如果你要包含(虚构的)模块SnazzyUIWidgets和SuperDataSync, 应用程序的模块声明看起来像这样:
图2-3 Title case filter
尽管Ajax从技术上讲是单页应用程序(理论上它们仅仅在第一次请求时加载HTML页面, 然后只需在DOM中更新区块), 我们通常会有多个子页面视图用于适当的显示给用户或者隐藏.
我们可以使用Angular的$route
服务来给我们管理这个场景. 让你指定路由, 对于浏览器指向给定的URL, Angular将加载并显示一个模板, 并且实例化一个控制器给模板提供上下文环境.
通过调用$routeProvider
服务的功能作为配置块来在你的应用程序中创建视图. 就像这样的伪代码:
图2-4 Foucs directive
Angular带有几个适用于单页应用程序的不错的功能来自动增强<form>
元素. 其中之一个不错的特性就是Angular让你在表单内的input中声明验证状态, 并允许在整组元素通过验证的情况下才提交.
例如, 如果我们创建一个登录表单, 我们必须输入一个名称和email, 但是有一个可选的年龄字段, 我们可以在他们提交到服务器之前验证多个用户输入. 如下加载这个例子到浏览器中将显示如图2-5所示:
图2-5. Form validation
我们还希望确保用户在名称字段输入文本, 输入正确形式的email地址, 以及他可以输入一个年龄, 它才是有效的.
我们可以在模板中做到这一点, 使用Angular的<form>
扩展和各个input元素, 就像这样:
在前两章中, 我们看到了Angular中所有最常用的功能(特性). 对每个功能的讨论, 许多额外的细节信息都没有覆盖到. 在下一章, 我们将让你通过研究一个典型的工作流程了解更多的信息.