GVKun编程网logo

AngularJS中是否提供自动依赖注入?(angular依赖注入的三种方式)

27

对于AngularJS中是否提供自动依赖注入?感兴趣的读者,本文将会是一篇不错的选择,我们将详细介绍angular依赖注入的三种方式,并为您提供关于30行代码让你理解angular依赖注入:angul

对于AngularJS中是否提供自动依赖注入?感兴趣的读者,本文将会是一篇不错的选择,我们将详细介绍angular依赖注入的三种方式,并为您提供关于30行代码让你理解angular依赖注入:angular 依赖注入原理、Angular 6提供了 – 如何自定义@Injectable()提供程序以进行依赖注入?、Angular JS中的依赖注入、angularjs – Angular Directive中的依赖注入的有用信息。

本文目录一览:

AngularJS中是否提供自动依赖注入?(angular依赖注入的三种方式)

AngularJS中是否提供自动依赖注入?(angular依赖注入的三种方式)

我想自动依赖注入一个Angular内置服务到Angular模块/ app中的所有服务.

我要注入的服务是… $exceptionHandler

我不希望$exceptionHandler成为全局…例如我不想做 …

window.$exceptionHandler = $exceptionHandler

但我也不希望依赖注入$exceptionHandler手动使用…

angular.module('myApp').factory('myService',['$exceptionHandler',function ($exceptionHandler) {

是否可以自动将Angular内置服务注入Angular模块/应用程序中的所有服务?

非常感谢

解决方法

通过嵌套模块可以使它更方便.在根(或全局)模块中,注入$exceptionHandler以及您创建或想要使用的所有其他模块.根模块的所有子模块都会有$exceptionHandler注入而不会更加轻松.但是,您仍然必须在控制器和工厂函数定义中命名$exceptionHandler,因此不可能完全摆脱注入伪影.

例:

app.js

angular.module('app',['ionic','$exceptionHandler','ngCordova','app.home','app.impressum'])

.run(function ($ionicPlatform,$state) {
   ..
})
.config(function ($stateProvider,$urlRouterProvider,$provide,$exceptionHandler,$ionicConfigProvider,$compileProvider) {

    $stateProvider
        .state('app',{
            ...
        })
    }
);

现在app.home-Module:

home.js

angular.module('app.home',['app.home.controller','app.home.factory']);

家用/ controller.js

angular.module('app.home.controller',[])
  .controller('homeController',function ($scope,$exceptionHandler) {
    ...
  });

app.home.factory和app.impressum的三个模块非常相似,所以我把它留给你.

如您所见,您仍然需要将$exceptionHandler放入控制器的函数参数中,但模块本身不需要注入,因为它继承了其父模块app.home和app的所有注入.

通过在AngularJS应用程序中使用模块层次结构,可以在适当的位置进行注入…对于整个应用程序,模块组或仅在单个模块上更全局.此外,我们为App的部分提供了一个非常干净的结构.

30行代码让你理解angular依赖注入:angular 依赖注入原理

30行代码让你理解angular依赖注入:angular 依赖注入原理

http://www.cnblogs.com/etoah/p/5460441.html

依赖注入(Dependency Injection,简称DI)是像C#,java等典型的面向对象语言框架设计原则控制反转的一种典型的一种实现方式,angular把它引入到js中,介绍angular依赖注入的使用方式的文章很多,
angular官方的文档,也有很详细的说明。但介绍原理的较少,angular代码结构较复杂,文章实现了一简化版本的DI,核心代码只有30行左右,相看实现效果(可能需FQ)或查看源码

这篇文章用尽量简单的方式说一说 angular依赖注入的实现。

简化的实现原理

要实现注入,基本有三步:

  1. 得到模块的依赖项
  2. 查找依赖项所对应的对象
  3. 执行时注入

1. 得到模块的依赖项

javascript 实现DI的核心api是Function.prototype.toString,对一个函数执行toString,它会返回函数的源码字符串,这样我们就可以通过正则匹配的方式拿到这个函数的参数列表:

function extractArgs(fn) { //angular 这里还加了注释、箭头函数的处理
            var args = fn.toString().match(/^[^\(]*\(\s*([^\)]*)\)/m);
            return args[1].split(',');
        }

2. 查找依赖项所对应的对象

java与.net通过反射来获取依赖对象,js是动态语言,直接一个object[name]就可以直接拿到对象。所以只要用一个对象保存对象或函数列表就可以了

createInjector(cache) {
            this.cache = cache;

        }
angular.module = function () {
            modules = {};
            injector = new createInjector(modules);
            return {
                injector: injector,
                factory: function (name, fn) {
                    modules[name.trim()] = this.injector.invoke(fn); 
                    return this;
                }
            }
        };

3. 执行时注入

最后通过 fn.apply方法把执行上下文,和依赖列表传入函数并执行:

createInjector.prototype = {
            invoke: function (fn, self) {
                argsstring = extractArgs(fn);
                args = [];
                argsstring.forEach(function (val) {
                    args.push(this.cache[val.trim()]);
                }, this);
                return fn.apply(self, args);
            }
        };

简化的全部代码和执行效果见(可能需FQ):http://plnkr.co/edit/sJiIbzEXiqLLoQPeXBnR?p=preview
或查看源码

这里是简化的版本,实际angular的实现考虑了很多问题,如模块管理,延迟执行等

angular 的实现

为了简单,我们也按这三步来介绍angular DI

  1. 得到模块的依赖项
  2. 查找依赖项所对应的对象
  3. 执行时注入

注:以下代码行数有就可能变

1. 得到模块的依赖项

https://github.com/angular/angular.js/blob/master/src%2Fauto%2Finjector.js#L81

var ARROW_ARG = /^([^\(]+?)=>/;
var FN_ARGS = /^[^\(]*\(\s*([^\)]*)\)/m;
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;

extractArgs(fn) {
  var fnText = fn.toString().replace(STRIP_COMMENTS, ''),
      args = fnText.match(ARROW_ARG) || fnText.match(FN_ARGS);
  return args;
}

2. 查找依赖项所对应的对象

https://github.com/angular/angular.js/blob/master/src%2Fauto%2Finjector.js#L807

getService(serviceName, caller) {
      if (cache.hasOwnProperty(serviceName)) {
        if (cache[serviceName] === INSTANTIATING) {
          throw $injectorminerr('cdep',21)">'Circular dependency found: {0}',
                    serviceName + ' <- ' + path.join(' <- '));
        }
        return cache[serviceName];
      } else {
        try {
          path.unshift(serviceName);
          cache[serviceName] = INSTANTIATING;
          return cache[serviceName] = factory(serviceName, caller);
        } catch (err) {
          if (cache[serviceName] === INSTANTIATING) {
            delete cache[serviceName];
          }
          throw err;
        } finally {
          path.shift();
        }
      }
    }

3. 执行时注入

https://github.com/angular/angular.js/blob/master/src%2Fauto%2Finjector.js#L831

得到参数:

injectionArgs(fn, locals, serviceName) {
      var args = [],
          $inject = createInjector.$$annotate(fn, strictDi, serviceName);

      for (var i = 0, length = $inject.length; i < length; i++) {
        var key = $inject[i];
        if (typeof key !== 'string') {
          'itkn',
                  'Incorrect injection token! Expected service name as string,got {0}', key);
        }
        args.push(locals && locals.hasOwnProperty(key) ? locals[key] :
                                                         getService(key, serviceName));
      }
      return args;
    }

调用

https://github.com/angular/angular.js/blob/master/src%2Fauto%2Finjector.js#L861

invoke(fn, self, serviceName) {
      typeof locals === 'string') {
        serviceName = locals;
        locals = null;
      }

      var args = injectionArgs(fn, locals, serviceName);
      if (isArray(fn)) {
        fn = fn[fn.length - 1];
      }

      if (!isClass(fn)) {
        // http://jsperf.com/angularjs-invoke-apply-vs-switch
        // #5388
        ;
      } else {
        args.unshift(null);
        new (Function.prototype.bind.apply(fn, args))();
      }
    }

angular模块管理,深坑

angular在每次应用启动时,初始化一个Injector实例:

https://github.com/angular/angular.js/blob/master/src/Angular.js#L1685

var injector = createInjector(modules, config.strictDi);

由此代码可以看出对每一个Angular应用来说,无论是哪个模块,所有的"provider"都是存在相同的providerCache或cache中

所以会导致一个被誉为angular模块管理的坑王的问题:
module 并没有什么命名空间的作用,当依赖名相同的时候,后面引用的会覆盖前面引用的模块。

具体的示例可以查看:

http://plnkr.co/edit/TZ7hpMwuxk0surlcWDvU?p=preview

注:angular di用本文的调用方式压缩代码会出问题:可以用g-annotate转为安全的调用方式。

到此angular di的实现原理已完成简单的介绍,angular用了项目中几乎不会用到的api:Function.prototype.toString 实现依赖注入,思路比较简单,但实际框架中考虑的问题较多,更加详细的实现可以直接看angular的源码。

以后会逐步介绍angular其它原理。

转载时请注明源出处:http://www.cnblogs.com/etoah/p/5460441.html

分类: Angular

Angular 6提供了 – 如何自定义@Injectable()提供程序以进行依赖注入?

Angular 6提供了 – 如何自定义@Injectable()提供程序以进行依赖注入?

在Angular 5中,如果我使用AbstractClassService和ExtendedClassService来扩展抽象,我可以在我的NgModule的providers数组中执行此操作:
@NgModule({
  providers: [
    {provide: AbstractClassService,useClass: ExtendedClassService}
  ]
})
export class AppModule {}

这将允许我将ExtendedClassService与另一个进行切换以进行测试或非常容易.这仍然可以使用Angular 6完成,但是有一个新的providedIn选项可以在服务本身中设置以减少包大小:

@Injectable({providedIn: 'root'})
export class ExtendedClassService extends AbstractClassService {}

有没有办法让我在使用新的provideIn时完成与Angular 5相同的操作?像这样的东西:

@Injectable({providedIn: 'root',provide: AbstractClassService})
export class ExtendedClassService extends AbstractClassService {}
我需要做两件事.

首先,在创建继承类时使用implements而不是extends,并且不要在那里使用providedIn键:

@Injectable() // removed providedIn
export class ExtendedClassService implements AbstractClassService {}

其次,将提供者指令添加到抽象类中:

@Injectable({providedIn: 'root',useClass: ExtendedClassService})
export abstract class AbstractClassService {}

其他提供程序配置(useValue,useExisting,useFactory)也可以在那里使用.

凭借this comment获得Abinesh的信用,这使我获得了the linked blog post.非常感谢博客作者!

Angular JS中的依赖注入

Angular JS中的依赖注入

我已经阅读了AngularJS文档,但仍然没有我知道的答案。

为什么要使用两次?一次作为数组元素,第二次作为函数参数。

someModule.controller('MyController',['$scope','greeter',function($scope,greeter) {
  // ...
}]);

angularjs – Angular Directive中的依赖注入

angularjs – Angular Directive中的依赖注入

为什么在通过数组注释通过require但其他依赖项完成的指令中注入Controller?

解决方法

需要一个控制器

如果要共享控制器的同一实例,则使用require.

require确保存在另一个指令,然后将其控制器作为链接函数的参数.因此,如果您在一个元素上有两个指令,那么您的指令可能需要存在另一个指令并获得对其控制器方法的访问权限.一个常见的用例是要求ngModel.

^ require,添加了插入符号,除了当前元素之外还检查上面指令的元素,以尝试查找其他指令.这允许您创建复杂的组件,其中“子组件”可以通过其控制器与父组件通信,从而产生很好的效果.示例可以包括标签,其中每个窗格可以与整个标签通信以处理切换;手风琴套装可以确保一次只开一个;等等

在任何一种情况下,您必须一起使用这两个指令才能使用. require是一种在组件之间进行通信的方式.

礼貌Josh David Miller

How to require a controller in an angularjs directive

对于数组注释原因,请看一下这些东西

Why is the function in angular’s DI inline annotation a array element?

我们今天的关于AngularJS中是否提供自动依赖注入?angular依赖注入的三种方式的分享就到这里,谢谢您的阅读,如果想了解更多关于30行代码让你理解angular依赖注入:angular 依赖注入原理、Angular 6提供了 – 如何自定义@Injectable()提供程序以进行依赖注入?、Angular JS中的依赖注入、angularjs – Angular Directive中的依赖注入的相关信息,可以在本站进行搜索。

本文标签: