Angularjs Source Analysis of Injector_angularjs

Source: Internet
Author: User
Tags hasownproperty


Brief introduction



Injector is used for automatic injection of parameters, such as


function fn ($http, $scope, Aservice) {
}


Ng runs the $http, $scope, and Aservice is automatically passed in as a parameter for execution.



It's easy to understand that Injector did two things.


    1. Cache those service and inject it later as a parameter
    2. Analyze the parameter list to find the required parameter injection


The following source analysis how to achieve the above two things.



Structure



createInjector -> createInternalInjector  return: instanceInjector



So Createinjector () returns the Instanceinjector, which is structured as follows:


{
 Invoke:invoke,
 instantiate:instantiate,
 get:getservice,
 annotate:annotate,
 has: function (name) {return
  providercache.hasownproperty (name + providersuffix) | | cache.hasownproperty (name);
 }
}


SOURCE Analysis



1. Createinjector


function Createinjector (modulestoload, strictdi) {strictdi = (Strictdi = = true); var instantiating = {}, Providersuffix = ' Provider ', Path = [], loadedmodules = new HashMap ([], true),//preconfigured $provide, for Loadmodules call Registration Service Providercache = {$provide: {provider:supportobject (provider), FAC Tory:supportobject (Factory), Service:supportobject (service), Value:supportobject (value), CONSTANT:SU Pportobject (constant), decorator:decorator},//Providerinjector, instanceinjector two injector//Insta Nceinjector to provide service and other injection, providerinjector internal supply provider to obtain Providerinjector = (providercache. $injector = Createinter Nalinjector (Providercache, function () {Throw $injectorMinErr (' UNPR ', ' Unknown provider: {0} ', Path.join (' <-'))
     ; }, Strictdi)), Instancecache = {}, Instanceinjector = (instancecache. $injector = Createinternalinjector (instanc Ecache, function (servicename) {var provider =Providerinjector.get (servicename + providersuffix);
     Return Instanceinjector.invoke (provider. $get, provider, undefined, servicename);

 }, STRICTDI));

 Load Module ForEach (Loadmodules (modulestoload), function (FN) {instanceinjector.invoke (fn | | noop);});
return instanceinjector;

 }


2. $provide


$provide: {
  provider:supportobject (provider),
  Factory:supportobject (Factory),
  Service:supportobject (service),
  Value:supportobject (value),
  constant:supportobject (constant),
  decorator:decorator
}


2.1 SupportObject



For packing method, the method before wrapping accepts two parameters (key, value), after wrapping method can support incoming object parameter, namely multiple key-> value.


function SupportObject (delegate) {return
 function (key, value) {
  if (IsObject (key)) {
   ForEach key, Reverseparams (delegate));
  else {return
   delegate (key, value);}}
 ;
}


2.2 Provider



Review the way provider, service and factory are used


App.factory (' ServiceName ', function () {return {getname:function () {}, Setname:function () {}}});

App.service (' ServiceName ', function () {this.getname = function () {} this.setname = function () {}}); App.provider (' ServiceName ', function ($httpProvider) {//inject $httpprovider this. $get = function () {return {getName:
 function () {}, Setname:function () {}};

}
});
App.provider (' ServiceName ', {$get: function () {}});
 function provider (name, Provider_) {assertnothasownproperty (name, ' service '); When Provider_ is FN or array, other provider can be injected into the parameter//because Providerinjector.instantiate (provider_) can be passed on to other dependent provider// This is also provider and Service,factory method is not the same place if (Isfunction (provider_) | | IsArray (PROVIDER_)) {Provider_ = providerinjector.in
 Stantiate (Provider_);
 } if (!provider_. $get) {throw $injectorMinErr (' Pget ', ' provider ' {0} ' must define $get factory method. ", name);
return providercache[name + providersuffix] = Provider_; function factory (name, FACTORYFN) {returN Provider (name, {$get: Factoryfn}); function service (name, constructor) {return factory (name, [' $injector ', function ($injector) {return $injector. Inst
 Antiate (constructor);
}]);

 function value (name, Val) {return factory (name, Valuefn (Val));}


The final rollup to the provider implementation is to cache provider to Providercache for calling



Unlike other things, the implementation of constant is saved to Providercache and Instancecache, which can be injected into the definition of provider or the definition of service.


function constant (name, value) {
 assertnothasownproperty (name, ' constant ');
 Providercache[name] = value;
 Instancecache[name] = value;
}


2.3 Review Loadmodules


function Runinvokequeue (queue) {
 var i, II;
 for (i = 0, ii = queue.length i < II i++) {
  var Invokeargs = queue[i],
    Provider = Providerinjector.get (Invok Eargs[0]);
  In the format of the queue ($provide, factory, arguments]
  //Replaced, $provide. factory.apply ($provide, arguments);
  is to call the $provid Factory,service et
  provider[invokeargs[1]].apply (provider, invokeargs[2]);
 }


2.4 Decorator



Example:


Module.config (function ($provide) {
 $provide. Decorator (' Mail ', function ($delegate) {
  $delegate. ADDCC = function (cc) {
   this.cc.push (cc);
  };
  return $delegate;})


Using the example, the passed parameter $delegate is the original service instance, and you need to add methods on that instance, that is, the so-called adorner



Source:


function Decorator (ServiceName, DECORFN) {
 var origprovider = providerinjector.get (ServiceName + providersuffix),
   orig$get = Origprovider. $get;

 Origprovider. $get = function () {
  //The required service instance is generated through the provider obtained above, and then injected into the parameter list $delegate with the
  var originstance = Instanceinjector.invoke (Orig$get, origprovider);
  Return Instanceinjector.invoke (DECORFN, NULL, {$delegate: Originstance});}



3. Createinternalinjector



3.1 Overall structure



Get from cache, no words call factory to create, specifically see GetService parsing


function Createinternalinjector (cache, factory) {

 function GetService (serviceName) {
 }

 function Invoke ( FN, self, locals, serviceName) {
 }

 function Instantiate (Type, locals, serviceName) {
 } return

 {
  // EXECUTE FN, with parameter injection function
  Invoke:invoke,
  //instantiate FN, parameters can be injected into
  instantiate:instantiate,
  //Get provider or service
  Get:getservice,
  //Get the parameter list of the method for injection using
  annotate:annotate,
  //Confirm that provider or service
  has is included: function (name) {return
   providercache.hasownproperty (name + providersuffix) | | cache.hasownproperty (name);
  }
 };
}


3.2 Annotate



Get the parameter list for FN


Type1
function fn (A, B, c)-> [' A ', ' B ', ' C ']

//type2
[' A ', ' B ', fn]-> [' A ', ' B ']

//Type3
function fn () {}
fn. $inject = [' A ', ' C ']
-> [' A ', ' C ']


Source:


Function Annotate (FN, STRICTDI, name) {var $inject, Fntext, Argdecl, last; if (typeof fn = = ' function ') {if (!) (
   $inject = fn. $inject)) {$inject = []; if (fn.length) {//in strict mode or if (STRICTDI) {if (!isstring (name) | |!name) {name = Fn.name | | ANONFN (f
     n); } Throw $injectorMinErr (' strictdi ', ' {0} is not using explicit annotation and cannot being invoked in strict mode '
    , name);
    ///Remove the comment Fntext = fn.tostring (). Replace (strip_comments, ");
    All parameters are selected FN (a,b,c,d)-> ' a,b,c,d ' argdecl = Fntext.match (Fn_args); Split into Array ForEach (Argdecl[1].split (Fn_arg_split), function (ARG) {arg.replace (Fn_arg, function (all, underscore,
     Name) {$inject. push (name);
    });
   });
  fn. $inject = $inject;
  } else if (IsArray (FN)) {last = fn.length-1;
  ASSERTARGFN (Fn[last], ' FN ');
 $inject = Fn.slice (0, last);
 else {ASSERTARGFN (FN, ' fn ', true);
return $inject;

 }


3.3 GetService




3.4 Invoke


function Invoke (FN, self, locals, serviceName) {
 if (typeof locals = = ' string ') {
  serviceName = locals;
  locals = null;
 }

 var args = [],
   //Get parameter list
   $inject = Annotate (FN, STRICTDI, serviceName),
   length, I,
   key;

 for (i = 0, length = $inject. length; i < length; i++) {
  key = $inject [i];
  if (typeof key!== ' string ') {
   throw $injectorMinErr (' itkn ',
       ' incorrect injection ' token! Expected service name As String, got {0} ', key ';
  }
  Locals priority
  Args.push (
   locals && locals.hasownproperty (key)
   Locals[key]
   : GetService ( Key)
  );
 if (IsArray (FN)) {
  fn = fn[length];
 }

 Return fn.apply (self, args);



3.5 Instantiate


function instantiate (Type, locals, serviceName) {
 var constructor = function () {},
   instance, returnedvalue;
 
 When Type is array, gets the last argument, such as: [' $window ', function ($win) {}]
 Constructor.prototype = (IsArray (Type)? TYPE[TYPE.LENGTH-1]: Type). prototype;
 Instance = new constructor ();
 Invoke invoke Execute type method
 Returnedvalue = Invoke (type, instance, locals, serviceName);

 Return IsObject (returnedvalue) | | Isfunction (returnedvalue)? returnedvalue:instance;
}


The role of instantiate is to instantiate the type, which can be automatically passed in to the constructor during instantiation.


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.