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

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

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

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

5 Service 和 Factory的区别

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

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

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.) 

下面是完成同样功能的一个service和一个factory

var app = angular.module('app',[]);
 
app.service('helloWorldService', function(){
    this.hello = function() {
        return "Hello World";
    };});
 
app.factory('helloWorldFactory', function(){
    return {
        hello: function() {
            return "Hello World";
        }
    }});

当 helloWorldService 或者 helloWorldFactory中的任何一个注入到controller里面, 他们都有一个返回字符串"Hello World"的名称为 hello方法。 这个service 的构造函数只在声明时被实例化一次,并且在这个 factory 对象每次被注入时各种互相引用, 但这个 factory还是只是被实例化了一次。 所有的 providers 都是单例的。

既然都完成同样的功能,为什么会有这两种格式存在?factoryservice略微更灵活一些,因为它们可以使用new关键字返回函数(原文:Factories offer slightly more flexibility than services because they can return functions which can then be new'd)。 在其他地方,从面向对象编程的工厂模式来说。 一个factory可以是一个用于创建其他对象的对象。

app.factory('helloFactory', function() {
    return function(name) {
        this.name = name;
 
        this.hello = function() {
            return "Hello " + this.name;
        };
    };
});

这里有一个使用了前面提到的那个service和两个factory的controller 的例子。需要注意的是 helloFactory 返回的是一个函数,变量name的值是在对象使用new关键字的时候设置。

app.controller('helloCtrl', function($scope, helloWorldService, helloWorldFactory, helloFactory) {
    init = function() {
      helloWorldService.hello(); //'Hello World'
 
      helloWorldFactory.hello(); //'Hello World'
 
      new helloFactory('Readers').hello() //'Hello Readers'
 
    }
    init();
});

在刚入门时候最好只使用services.

Factory更加适用于当你在设计一个需要私有方法的类的时候使用:

app.factory('privateFactory', function(){
    var privateFunc = function(name) {
        return name.split("").reverse().join(""); //reverses the name
    };
 
    return {
        hello: function(name){
          return "Hello " + privateFunc(name);
        }
    };});

在这个例子中privateFactory含有一个不能被外部访问的私有privateFunc函数。这种使用方式services也可以实现,但是使用Factory代码结构显得更加清晰。

6 不会使用 Batarang

Batarang 是用于开发和调试 AngularJS 应用的一个优秀的chrome浏览器插件。

Batarang 提供了模型浏览,可以查看Angular内部哪些模型已经绑定到作用域(scopes )。可以用于需要在运行时查看指令中的隔离作用域(isolate scopes)绑定的值。

Batarang 还提供了依赖关系图。 对于引入一个未测试的代码库, 这个工具可以快速确定哪些services应该得到更多的关注。

最后, Batarang提供了性能分析。 AngularJS 虽然是高性能开箱即用, 但是随着应用自定义指令和复杂的业务逻辑的增长,有时候会感到页面不够流畅。使用 Batarang 的性能分析工具可以很方便的查看哪些functions 在digest 周期中占用了更多的时间。这个工具还可以显示出整个监控树(full watch tree),当页面有太多的监控器(watch)时,这个功能就显得有用了。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/2a78eee7b4227bb90753aadf791d67d2.html