浅析AngularJS中的生命周期和延迟处理


Posted in Javascript onJune 18, 2015

这里,我们再讨论一些常用的高级的控制反转容器(Inversion of Control containers):延迟加载(lazy-loading),生命周期管理(lifetime management),以及延迟的创建/处理(deferred creation/resolution)。
 
延迟加载(Lazy-Loading)

所谓延迟加载就是当你需要用到对象时候才对其进行实例化。许多依赖注入系统都会在一开始就创建组件,作为它的可依赖项目。不过有时候,直到在应用中用到它们之前,你都不会想去实例化这些组件。Angular 中,一个很好的例子就是,当你在配置的时候去设置一个行为,而该行为又会引用到一些还没创建的组件。

假设你想拦截系统内建的 $log 服务,因此你把它存在了 $rootScope 里面。当然我不建议这样做,不过这样举例比较简单有效。为了拦截,你在配置的时候用到了 $provide 然后调用修饰方法。如果这时你想直接引用 $rootScope 的话,由于循环引用你会拿到个异常。而解决案是通过 $injector 延迟加载 $rootScope 。

下面的代码只会在 $rootScope 第一次被使用的时候才去加载它。

 

$provide.decorator(, [, ,
   ($delegate, $injector) {
     log = $delegate.log.bind($delegate);
    $delegate.log = (msg) {
       rs = $injector.get();
       (rs.logs === undefined) {
        rs.logs = [];
      }
      rs.logs.push(msg);
      log(msg);
    };
     $delegate;
}]);

之后的调用都会拿到一样的单例 $rootScope。 这里有个可用例子。我之前好像听过有个(不对的)说法(Angular 只支持单例) … 当然不是真的。$injector 中的方法就是用来给你管理你的组件的生命周期的。

生命周期管理

生命周期涉及到你如何管理组件的实例。默认情况,当你注入一个 Angular 的依赖,依赖注入就会帮你创建它的一个副本然后在你的应用里面重用它。大多数情况下这确实是我们所期待的。而有些情况下,会要求同一组件的多个实例。假设下面的计数服务:

 
 

Counter($log) {
  $log.log();
}
 
angular.extend(Counter.prototype, {
  count: 0,
  increment: () {
    .count += 1;
     .count;
  }
});
 
Counter.$inject = [];
 
app.service(, Counter);

你的应用要跟踪不同的计数器。而你注入该服务后,总会拿到一样的计数器。这难道是 Angular 的限制?

当然不是。重复一次,通过 $injector 服务你可以在任何时候创建一个新副本。下面的代码用了两个独立的计数器:
 

app.run([, , ,
   (rs, c, i) {
    rs.count = c.count;
    rs.update = c.increment;
    rs.update2 = () {
       c = i.instantiate(Counter);
      rs.count2 = c.count;
      rs.update2 = () {
        c.increment();
        rs.count2 = c.count;
      };
    };
  }]);

你可以看到计数器都是被独立的实例跟踪的,这里是可用例子。如果你需要经常生成新实例,你可以像这样注册服务:
 

app.factory(, [,
   (i) {
     {
      getCounter: () {
         i.instantiate(Counter);
      }
    };
  }]);

产生一个需要的实例就是那么简单,而且你可以用你的工厂组件来代替 $injector:
 

app.run([, ,
   (rs, cf) {
     c1 = cf.getCounter(),
      c2 = cf.getCounter();
    rs.count = c1.count;
    rs.update = c1.increment;
    rs.count2 = c2.count;
    rs.update2 = () {
      rs.count2 = c2.increment();
    };
  }]);

你可以看看这个完整版本的可用例子。如你所见,用 Angular 的内建依赖注入是完全有可能管理你组件的生命周期的。那延迟处理(deferred resolution)又怎样呢 ? 比如说,有些组件你需要在 Angular 已经配置好之后引入,而且需要用它们的依赖来包装起来。

延迟处理(Deferred Resolution)

我们已经介绍了在 Angular 中可以延迟处理依赖的一种方法。当你想包装某些东西的时候,你可以调用 $injector 服务的 instantiate ,然后它可以通过参数嗅探来解决依赖,看起来就像用 $inject 的静态属性一样,或者也可以通过检查你传给它的数组来实现的。也就是说,下面这个是完全有效写法:
 

$injector.instantiate(['dependency', Constructor]);

你还可以调用带装饰数组的方法。假设你有一个方法依赖于 $log 服务,你可以运行时通过延迟处理来调用它,像下面这样:

 

myFunc = [, ($log) {
  $log.log();
}];
$injector.invoke(myFunc);

你可以看看这个可用例子(打开你的控制台,看看你按下按钮之后发生了什么)。
 
总结

综上所述,Angular 的依赖注入提供了许多高级特性,你在商业应用生产线上会希望并且经常会用到它们。factories, services, 和 providers 的便捷让 Angular 开发者常常产生错觉,认为这里只有唯一选项可用。而神奇之处在于 $injector 服务,你可以用它生成所需的单例,创建新的组件或者动态引用带依赖的方法。

最后要注意的是,你客户端代码里面的注入即使在 Angular 之外也是可用的。我们来看一个在 Angular 之外包装的,通过注入调用 $log 服务的例子,点这里。为什么要把 ‘ng' 传入方法的数组?它是 Angular 的核心模块,当你包装你的模块的时候是会被隐式添加的,但是如果你的指令要生成自己的注入实例的时候,你就必须显式添加了。

Javascript 相关文章推荐
修改jQuery.Autocomplete插件 支持中文输入法 避免TAB、ENTER键失效、导致表单提交
Oct 11 Javascript
实现变速回到顶部的JavaScript代码
May 09 Javascript
javascript使用中为什么10..toString()正常而10.toString()出错呢
Jan 11 Javascript
Node.js中创建和管理外部进程详解
Aug 16 Javascript
js中实现多态采用和继承类似的方法
Aug 22 Javascript
jQuery+Ajax实现无刷新分页
Oct 30 Javascript
ReactJs快速入门教程(精华版)
Nov 28 Javascript
如何实现星星评价(jquery.raty.js插件)
Dec 21 Javascript
Vue.js与 ASP.NET Core 服务端渲染功能整合
Nov 16 Javascript
解决vue单页使用keep-alive页面返回不刷新的问题
Mar 13 Javascript
JavaScript面向对象的程序设计(犯迷糊的小羊)
May 27 Javascript
vue实现拖拽的简单案例 不超出可视区域
Jul 25 Javascript
Node.js事件驱动
Jun 18 #Javascript
详解AngularJS的通信机制
Jun 18 #Javascript
javascript背景时钟实现方法
Jun 18 #Javascript
移动Web中图片自适应的两种JavaScript解决方法
Jun 18 #Javascript
javascript随机显示背景图片的方法
Jun 18 #Javascript
利用JavaScript的AngularJS库制作电子名片的方法
Jun 18 #Javascript
javascript实现根据时间段显示问候语的方法
Jun 18 #Javascript
You might like
zf框架的数据库追踪器使用示例
2014/03/13 PHP
Zend Framework页面缓存实例
2014/06/25 PHP
php中html_entity_decode实现HTML实体转义
2018/06/13 PHP
javascript 常用关键字列表集合
2007/12/04 Javascript
Javascript中判断变量是数组还是对象(array还是object)
2013/08/14 Javascript
JavaScript常用的返回,自动跳转,刷新,关闭语句汇总
2015/01/13 Javascript
详解JavaScript中jQuery和Ajax以及JSONP的联合使用
2015/08/13 Javascript
学习JavaScript设计模式之策略模式
2016/01/12 Javascript
JS实现类似51job上的地区选择效果示例
2016/11/17 Javascript
微信小程序 常见问题总结(4058,40013)及解决办法
2017/01/11 Javascript
通过jsonp获取json数据实现AJAX跨域请求
2017/01/22 Javascript
JavaScript编程设计模式之构造器模式实例分析
2017/10/25 Javascript
Vue.js 通过jQuery ajax获取数据实现更新后重新渲染页面的方法
2018/08/09 jQuery
jQuery实现参数自定义的文字跑马灯效果
2018/08/15 jQuery
傻瓜式解读koa中间件处理模块koa-compose的使用
2018/10/30 Javascript
js 计算图片内点个数的示例代码
2019/04/04 Javascript
js实现前端界面导航栏下拉列表
2020/08/27 Javascript
jquery简易手风琴插件的封装
2020/10/13 jQuery
[01:54]TI珍贵瞬间系列(五):压力
2020/08/29 DOTA
Python自定义装饰器原理与用法实例分析
2018/07/16 Python
python广度优先搜索得到两点间最短路径
2019/01/17 Python
python的debug实用工具 pdb详解
2019/07/12 Python
Python解压 rar、zip、tar文件的方法
2019/11/19 Python
Python常用模块logging——日志输出功能(示例代码)
2019/11/20 Python
Window10上Tensorflow的安装(CPU和GPU版本)
2020/12/15 Python
html5 Canvas绘制线条 closePath()实例代码
2012/05/10 HTML / CSS
一些常用的HTML5模式(pattern) 总结
2015/07/14 HTML / CSS
写出SQL四条最基本的数据操作语句(DML)
2012/12/12 面试题
Linux开机引导的步骤是什么
2014/02/26 面试题
蔬菜基地的创业计划书
2014/01/06 职场文书
诚信贷款承诺书
2014/05/30 职场文书
计算机毕业生自荐信
2014/06/12 职场文书
2015年党员公开承诺书范文
2015/01/22 职场文书
加薪通知
2015/04/25 职场文书
催款函范文
2015/06/24 职场文书
导游词之丽江普济寺
2019/10/22 职场文书