Einführung
Injektor wird verwendet, um beispielsweise eine automatische Parameterinjektion durchzuführen
Funktion fn ($ http, $ scope, asservice) {}Wenn NG ausgeführt wird, wird $ http, $ scope und Asservice automatisch als Parameter für die Ausführung übergeben.
Es ist eigentlich einfach, es herauszufinden, Injektor hat zwei Dinge getan
Der folgende Quellcode analysiert, wie die oben genannten zwei Dinge implementiert werden.
Struktur
createInjector -> createInternalInjector return: instanceInjector
So createInjector () retektiert InstanceInjector, die Struktur lautet wie folgt:
{Invoke: Invoke, Instantiate: Instantiert, Get: GetService, Annotate: Annotate, Has: Funktion (Name) {return Providercache.hasownProperty (Name + Providersuffix) || Cache.hasownProperty (Name); }}Quellcodeanalyse
1. CreateInjector
Funktion createInjector (modulestoload, strictdi) {strictdi = (strictdi === true); var Instantiating = {}, Providersuffix = 'Provider', Path = [], LoadedModules = new HashMap ([], True), // vor-konfigurieren $ für den Anrufregistrierungsdienst in LoadModules usw. usw. SupportObject (Wert), konstant: SupportObject (konstant), Dekorateur: Dekorateur}}, // Providerinjector, InstanceInjector Zwei Injektoren // InstanceInjector bietet Dienst und andere Injektionen extern, und Providerinjector bietet Anbieter intern, um Providerinjector = (ProviderCache $ in Injector = Erstellen SieIniewer) () {$ injector = createIninctorinStorinalin (). $ InjectorMInerr ('unkanal, "Unbekannter Anbieter: {0}", path.join (' <- ')); Providersuffix); // Lademodul für Each (loadModules (modulestoload), Funktion (fn) {instanceInjector.invoke (fn || noop);}); return InstanceInjector;}2. $ sorge
$ bereitgestellt: {Provider: SupportObject (Anbieter), Fabrik: SupportObject (Fabrik), Service: SupportObject (Service), Wert: SupportObject (Wert), Konstant: SupportObject (konstant), Dekorateur: Dekorateur}2.1 SupportObject
Für Verpackungsmethoden akzeptiert die Methode vor der Verpackung zwei Parameter (Schlüssel, Wert). Die verpackte Methode kann die Übergabe von Objektparametern unterstützen, dh mehrere Tasten -> Werte.
Funktion SupportObject (Delegate) {Rückgabefunktion (Schlüssel, Wert) {if (isObject (Schlüssel)) {foreach (Schlüssel, ReverseParams (delegate)); } else {return delegate (Schlüssel, Wert); }};}2.2 Anbieter
Überprüfen Sie, wie Anbieter, Service und Fabrik verwendet werden
app.factory ('serviceName', function () {return {getName: function () {}, setName: function () {}}}); App.Service ('servicename', function () {this.getName = function () {} this.setname = funktions () {{}}); function ($ httpprovider) {// $ httpprovider this. $ get = function () {return {getName: function () {}, setName: function () {}}; AssertnothasownProperty (Name, "Service"); // When provider_ is fn or array, other providers can be injected into parameters// Because when providerInjector.instantiate(provider_) can be passed into other providers that depend on // This is also the difference between provider and service and factory methods if (isFunction(provider_) || isArray(provider_)) { provider_ = providerInjector.instantiate(provider_); } if (! Anbieter _. $ get) {throw $ InjectorMInerRr ('pGet', "Provider '{0}' muss $ Get Factory -Methode definieren.", Name); } return providercache [name + providersuffix] = provider _;} function Factory (Name, FactoryFn) {return Provider (Name, $ get: factoryFn}); } Funktionsdienst (Name, Konstruktor) {return factory (name, ['$ injector', function ($ injector) {return $ injector.inStantiate (Konstruktor);}]); }Schließlich werden der Anbieter für den Anbieter für den Anruf für den Anruf zusammengefasst.
Was sich von den anderen unterscheidet, ist die Implementierung von Konstante, die in Providercache bzw. Instancecache gespeichert wird, damit sowohl der Anbieter als auch der Dienst injiziert werden können.
Funktionskonstante (Name, Wert) {AssertnothasownProperty (Name, 'Constant'); ProviderCache [Name] = Wert; InstanceCache [Name] = Wert;}2.3 Überprüfen Sie LoadModules
Funktion Runinvokequeue (Warteschlange) {var i, ii; für (i = 0, ii = queue.Length; i <ii; i ++) {var invokeargs = queue [i], Provider = Providerinjector.get (invokeargs [0]); // Das Format der Warteschlange wird in [$ liefer, fabrik, argumente] // nach dem Ersatz, $ ciply.factory.apply ($ liefern, argumente) gespeichert; // Es soll $ Provid Factory, Service und anderer Anbieter [invokeargs [1]] anrufen. }}2.4 Dekorateur
Beispiel:
module.config (Funktion ($ bereitgestellt) {$ ciples.decorator ('mail', function ($ delegate) {$ delegate.addcc = function (cc) {this.cc.push (cc);}; $ delegate;});})Mit dem Beispiel ist ersichtlich, dass der übergebene Parameter $ Delegate die ursprüngliche Serviceinstanz ist, und Sie müssen dieser Instanz eine Methode hinzufügen, die der sogenannte Dekorateur ist
Quellcode:
Funktionsdekorator (Servicename, Decorfn) {var origprovider = providerinjector.get (Servicename + Providersuffix), orig $ get = origProvider. $ GET; origProvider. $ get = function () {// Generieren Sie die erforderliche Serviceinstanz über den oben erhaltenen Anbieter und injizieren Sie sie mit $ delegate var OriginStance = InstanceInjector.invoke (orig $ GET, origProvider); return InstanceInjector.invoke (Decorfn, Null, {$ delegate: OriginStance}); };}3.. CreateInternalinjector
3.1 Gesamtstruktur
// Rufen Sie es von Cache aus, wenn nicht, die Fabrik, um es zu erstellen. Siehe GetService -Analyse für Details
Funktion createInternalinjector (Cache, Werksfabrik) {Funktion getService (Servicename) {} Funktion Invoke (Fn, Selbst, Einheimische, Servicename) {} Funktion Instantiate (Typ, Einheimische, servicename) {} return {// Fn, Invoke: Invoke: // //. // Erhalten Sie die Parameterliste der Methode zur Injektionsannotierung: Annotate, // Bestätigen Sie, ob sie Anbieter oder Dienst enthält: Funktion (Name) {return Providercache.hasownProperty (Name + Providersuffix) || Cache.hasownProperty (Name); }};}3.2 Annotate
Holen Sie sich die Parameterliste von FN
// Typ1Function fn (a, b, c) -> ['a', 'b', 'c'] // Typ2 ['a', 'b', fn] -> ['a' B '] // Typ3function fn () {} fn.Quellcode:
Funktion kommentieren (fn, strictdi, name) {var $ inject, fntext, argdecl, last; if (typeof fn === 'Funktion') {if (! ($ inject = fn. $ inject)) {$ inject = []; if (fn.length) {// if (strictdi) {if (! isstring (name) ||! name) {name = fn.name || anonfn (fn); } throw $ InjectorMInerr ('strictdi', '{0} verwendet keine explizite Annotation und kann nicht im strengen Modus aufgerufen werden', Name); } // Entfernen Sie den Kommentar fntext = fn.toString (). Ersetzen (Strip_Coments, ''); // Alle Parameter Fn (a, b, c, d) -> 'a, b, c, d' argdecl = fntext.match (fn_args); // In Array foreach (argdecl [1] .Split (fn_arg_split), function (arg) {arg.Replace (fn_arg, function (alle, unterstrich, name) {$ inject.push.push (Name);});}); }); } fn. $ inject = $ inject; }} else if (isArray (fn)) {last = fn.length - 1; Assertargfn (fn [letztes], 'fn'); $ inject = fn.lice (0, letztes); } else {assertargfn (fn, 'fn', true); } return $ inject;}3.3 GetService
// Wenn es keinen Dienst im Cache gibt, geben Sie sonst ein, cache [serviceName] = Instantiating, um eine Marke zu erstellen // Da der nächste Anruffabrik (Servicename) tatsächlich ein rekursiver Anruf // Funktion (serviceName) {// var provider = providerinjector.get (serviceName + providersUnding, providersufl, ////////////////////// -Rückgabeinstanz). Servicename); //} // InstanceInjector.invoke (Anbieter. $ injectormerr ('CDEP', "Zirkulare Abhängigkeit gefunden: {0} ', Servicename +' <- ' + Pathoin (' <- '); (Err) {if (cache [serviceName] === Instantiating) {cache [servicename];3.4 aufrufen
Funktion Invoke (Fn, Selbst, Einheimische, Servicename) {if (typeof locals === 'String') {ServicEname = Localen; Einheimische = null; } var args = [], // Die Parameterliste $ inject = Annotate (fn, strictdi, serviceName), Länge, i, Schlüssel; für (i = 0, Länge = $ inject.length; i <Länge; i ++) {Key = $ inject [i]; if (typeof key! } // Einheimische Priorität args.push (Einheimische && locals.hasownProperty (Schlüssel)? Einheimische [Schlüssel]: GetService (Schlüssel)); } if (isArray (fn)) {fn = fn [Länge]; } return fn.apply (self, args);}3.5 Sofortieren
Funktion Instantiate (Typ, Einheimische, Servicename) {var constructor = function () {}, Instanz, returnedValue; // Wenn ein Array ist, erhalten Sie den letzten Parameter, wie z. Instance = New Constructor (); // rufen Sie auf, um die Typ -Methode zurückzuführen. ReturnedValue = Invoke (Typ, Instanz, Einheimische, Servicename); Return isObject (zurückgegebener Wert) || isFunction (returnedValue)? returnedValue: Instanz;}Die Funktion des Instanzials besteht darin, den Typ zu instanziieren, und Parameter können während des Instanziierungsprozesses automatisch in den Konstruktor übergeben werden.