浅析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 相关文章推荐
JavaScript定时器详解及实例
Aug 01 Javascript
extjs render 用法介绍
Sep 11 Javascript
js图片预加载示例
Apr 30 Javascript
JS的location.href跳出框架打开新页面的方法
Sep 04 Javascript
node.js中的http.request.end方法使用说明
Dec 10 Javascript
自定义Angular指令与jQuery实现的Bootstrap风格数据双向绑定的单选与多选下拉框
Dec 12 Javascript
AngularJS 入门教程之事件处理器详解
Aug 19 Javascript
Node.js Sequelize如何实现数据库的读写分离
Oct 23 Javascript
Vue.js实现表格动态增加删除的方法(附源码下载)
Jan 20 Javascript
jQuery 表单序列化实例代码
Jun 11 jQuery
Vue render渲染时间戳转时间,时间转时间戳及渲染进度条效果
Jul 27 Javascript
一文彻底理解js原生语法prototype,__proto__和constructor
Oct 24 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
php连接数据库代码应用分析
2011/05/29 PHP
利用PHP实现智能文件类型检测的实现代码
2011/08/02 PHP
destoon常用的安全设置概述
2014/06/21 PHP
PHP实现的redis主从数据库状态检测功能示例
2017/07/20 PHP
javascript中的undefined 与 null 的区别  补充篇
2010/03/17 Javascript
div拖拽插件——JQ.MoveBox.js(自制JQ插件)
2013/05/17 Javascript
js实现身份证号码验证的简单实例
2014/02/19 Javascript
jQuery基础知识点总结(DOM操作)
2016/06/01 Javascript
Vue.js学习笔记之 helloworld
2016/08/14 Javascript
Ajax使用原生态JS验证用户名是否存在
2020/05/26 Javascript
微信小程序 实现拖拽事件监听实例详解
2016/11/16 Javascript
基于Vuejs的搜索匹配功能实现方法
2018/03/03 Javascript
小程序云开发实战小结
2018/10/25 Javascript
微信小程序网络层封装的实现(promise, 登录锁)
2019/05/08 Javascript
ES6 Array常用扩展的应用实例分析
2019/06/26 Javascript
jquery树形插件zTree高级使用详解
2019/08/16 jQuery
vuejs中父子组件之间通信方法实例详解
2020/01/17 Javascript
简单了解JavaScript弹窗实现代码
2020/05/07 Javascript
[04:17]DOTA2完美盛典,rOtk、BurNIng携手巴图演唱《倔强》
2017/11/28 DOTA
[01:19:23]2018DOTA2亚洲邀请赛 4.5 淘汰赛 Mineski vs VG 第二场
2018/04/06 DOTA
Python多进程同步简单实现代码
2016/04/27 Python
python 字典 按key值大小 倒序取值的实例
2018/07/06 Python
python使用循环打印所有三位数水仙花数的实例
2018/11/13 Python
python画图把时间作为横坐标的方法
2019/07/07 Python
python创建属于自己的单词词库 便于背单词
2019/07/30 Python
运用PyTorch动手搭建一个共享单车预测器
2019/08/06 Python
与Django结合利用模型对上传图片预测的实例详解
2019/08/07 Python
Django中和时区相关的安全问题详解
2020/10/12 Python
用python读取xlsx文件
2020/12/17 Python
处理textarea中的换行和空格
2019/12/12 HTML / CSS
美国手工艺品市场的领导者:Annie’s
2019/04/04 全球购物
MyBag中文网:英国著名的时尚包袋电商零售网站
2020/07/31 全球购物
事业单位接收函
2014/01/10 职场文书
医学专业职业生涯规划范文
2014/02/05 职场文书
写求职信有哪些注意事项
2014/05/08 职场文书
小学语文教学随笔
2015/08/14 职场文书