设为首页收藏本站

LUPA开源社区

 找回密码
 注册
文章 帖子 博客
LUPA开源社区 首页 业界资讯 技术文摘 查看内容

AngularJS开发者最常犯的10个错误

2014-10-9 10:39| 发布者: joejoe0332| 查看: 3675| 评论: 0|原作者: LeoG0816, 砼砼, 柳絮飞_lilf, Boobs, James_飏|来自: oschina

摘要: AngularJS是如今最受欢迎的JS框架之一,简化开发过程是它的目标之一,这使得它非常适合于元型较小的apps的开发,但也扩展到具有全部特征的客户端应用的开发。易于开发、较多的特征及较好的效果导致了较多的应用,伴 ...

介绍

  AngularJS是如今最受欢迎的JS框架之一,简化开发过程是它的目标之一,这使得它非常适合于元型较小的apps的开发,但也扩展到具有全部特征的客户端应用的开发。易于开发、较多的特征及较好的效果导致了较多的应用,伴随而来的是一些陷阱。本文列举了AngularJS的一些共同的易于也问题的地方,尤其是在开发一个app的时候。


1. MVC目录结构

  AngularJS是一个缺乏较好的term的MVC框架,其models不像backbone.js中那样做为一个框架来定义,但其结构模式仍匹配的较好。当在一个MVC框架中作业时,基于文件类型将文件组合在一起是其共同的要求:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
templates/
    _login.html
    _feed.html
app/
    app.js
    controllers/
        LoginController.js
        FeedController.js
    directives/
        FeedEntryDirective.js
    services/
        LoginService.js
        FeedService.js
    filters/
        CapatalizeFilter.js

  这样的布局, 尤其是对那些有 Rails 背景的人来说, 看起来挺合理. 可是当 app 变得越来越庞大的时候, 这样的布局结构会导致每次都会打开一堆文件夹. 无论你是用 Sublime, Visual Studio, 还是 Vim with Nerd Tree, 每次都要花上很多时间滑动滚动条浏览这个目录树来查找文件.


  如果我们根据每个文件隶属的功能模块来对文件分组, 而不是根据它隶属的层:

1
2
3
4
5
6
7
8
9
10
11
12
13
app/
    app.js
    Feed/
        _feed.html
        FeedController.js
        FeedEntryDirective.js
        FeedService.js
    Login/
        _login.html
        LoginController.js
        LoginService.js
    Shared/
        CapatalizeFilter.js

  那么查找某个功能模块的文件就要容易得多, 自然可以提高开发的速度. 也许把 html 文件跟 js 文件放在混合放在一起做法不是每个人都能认同. 但是起码它省下宝贵的时间.


2、模块分组

一开始就将主模块中所有子模块展示出来是通常的做法。但是开始做一个小应用还好,但是做大了就不好管理了。

1
2
3
var app = angular.module('app',[]);app.service('MyService'function(){
    //service code});app.controller('MyCtrl', function($scope, MyService){
    //controller code});

一个比较好的办法是将相似类型的子模块分组:

1
2
3
var services = angular.module('services',[]);services.service('MyService'function(){
    //service code});var controllers = angular.module('controllers',['services']);controllers.controller('MyCtrl', function($scope, MyService){
    //controller code});var app = angular.module('app',['controllers', 'services']);

这个方法与上面那个方法效果差不多,但是也不很大。运用要分组的思想将使工作更容易。

1
2
3
4
5
6
var sharedServicesModule = angular.module('sharedServices',[]);
sharedServices.service('NetworkService'function($http){});
var loginModule = angular.module('login',['sharedServices']);
loginModule.service('loginService'function(NetworkService){});
loginModule.controller('loginCtrl'function($scope, loginService){});
var app = angular.module('app', ['sharedServices''login']);

当创建一个大的应用时,所有模块可能不会放在一页里,但是将模块根据类型进行分组将使模块的重用能力更强。


3 依赖注入

依赖注入是AngularJS最棒的模式之一。它使测试变得更加方便,也让它所依赖的对象变的更加清楚明白。AngularJS 对于注入是非常灵活的。一个最简单的方式只需要为模块将依赖的名字传入函数中:

1
2
3
4
var app = angular.module('app',[]);app.controller('MainCtrl'function($scope, $timeout){
    $timeout(function(){
        console.log($scope);
    }, 1000);});

这里,很清楚的是MainCtrl依赖于$scope和$timeout。

直到你准备投入生产并压缩你的代码。使用UglifyJS,上面的例子会变成:

1
2
var app=angular.module("app",[]);
app.controller("MainCtrl",function(e,t){t(function(){console.log(e)},1e3)})

现在AngularJS怎么知道MainCtrl依赖什么?AngularJS提供了一个非常简单的解决方案:把依赖作为一个字符串数组传递,而数组的最后一个元素是一个把所有依赖作为参数的函数。

1
2
3
4
app.controller('MainCtrl', ['$scope''$timeout'function($scope, $timeout){
    $timeout(function(){
        console.log($scope);
    }, 1000);}]);

接下来在压缩的代码中AngularJS也可以知道如何找到依赖:

1
app.controller("MainCtrl",["$scope","$timeout",function(e,t){t(function(){console.log(e)},1e3)}])

3.1 全局依赖

通常在写AngularJS应用时会有一个对象作为依赖绑定到全局作用域中。这意味着它在任何AngularJS的代码中都可用,但这打破了依赖注入模型同时带来一些问题,特别是在测试中。

AngularJS把这些全局变量封装到模块中,这样它们可以像标准AngularJS模块一样被注入。

Underscore.js是很棒的库,它把Javascript代码简化成了函数模式,并且它可以被转化成一个模块:

1
2
3
4
5
6
7
var underscore = angular.module('underscore', []);underscore.factory('_'function() {
  return window._; //Underscore must already be loaded on the page});var app = angular.module('app', ['underscore']);app.controller('MainCtrl', ['$scope', '_', function($scope, _) {
    init = function() {
          _.keys($scope);
      }
 
      init();}]);

它允许应用继续用AngularJS依赖注入的风格,也让underscore在测试的时候被交换出来。

这或许看上去不重要,像是一个无关紧要的工作,但如果你的代码正在使用use strict(应该使用),那么这就变得有必要了。


4 控制器膨胀

控制器是AngularJS应用中的肉和番茄。它很简单,特别是开始的时候,在控制器中放入过多的逻辑。控制器不应该做任何DOM操作或者有DOM选择器,这应该由使用ngModel的指令(directives)做的事。同样地,业务逻辑应该在服务(services)中,而不是 控制器。

数据也应该被存在服务(services)中,除非它已经和$scope关联。服务(services)是留存于整个应用生命周期的个体,同时控制器在应用各阶段间都是暂态的。如果数据被存在控制器中,那么当它被重新实例化的时候,就需要从其他地方抓取。即使数据被存储在localStorage中,获取数据也要比从Javascript变量中获取要慢几个数量级。

AngularJS在遵从简单责任原则(SRP)时工作地最好。如果控制器是视图和模型的协调者,那么它拥有的逻辑应该被最小化。这将使得测试变的更加简单。 


5 Service 和 Factory的区别

几乎每一个刚接触AngularJS的开发者,都会对这两个东西产生困惑。 虽然它们(几乎)实现了同样的效果,但真的不是语法糖。

这里是它们在 AngularJS 源码中的定义:

1
2
3
4
5
6
7
function factory(name, factoryFn) { return provider(name, { $get: factoryFn }); }
 
function service(name, constructor) {
    return factory(name, ['$injector'function($injector) {
      return $injector.instantiate(constructor);
    }]);
  }

从源码上看显然 service 函数只是调用 factory 函数,然后 factory 函数再调用 provider 函数。事实上,value、constant和decorator 也是 AngularJS 提供的对 provider 的封装,但对它们使用场景不会有这种困惑,并且文档描述也非常清晰。

那么Service 仅仅是单纯的调用了一次 factory 函数吗? 重点在 $injector.instantiate 中; 在这个函数里service会接收一个由$injector 使用new关键字去实例化的一个构造器对象。(原文:with in this function $injector creates a new instance of the service's constructor function.) 



酷毙

雷人

鲜花

鸡蛋

漂亮
  • 快毕业了,没工作经验,
    找份工作好难啊?
    赶紧去人才芯片公司磨练吧!!

最新评论

关于LUPA|人才芯片工程|人才招聘|LUPA认证|LUPA教育|LUPA开源社区 ( 浙B2-20090187 浙公网安备 33010602006705号   

返回顶部