Introdução
O injetor é usado para realizar injeção automática de parâmetros, por exemplo
função fn ($ http, $ SCOPE, ASERVICE) {}Quando o NG é executado, $ HTTP, $ SCOPE, ASERVICE será transmitido automaticamente como parâmetros para execução.
Na verdade, é fácil descobrir, o injetor fez duas coisas
O seguinte código -fonte analisa como implementar as duas coisas acima.
estrutura
createInjector -> createInternalInjector return: instanceInjector
Portanto, CreateInjector () Retorna Instância Injetor, a estrutura é a seguinte:
{Invoke: Invoke, instanciado: instanciado, get: getService, anote: anote, tem: function (nome) {return providercache.hasownproperty (nome + provendersuffix) || Cache.HasownProperty (nome); }}Análise do código -fonte
1. CreateInjector
função createInjector (modulestoload, strictdi) {strictdi = (strictdi === true); var instantiating = {}, providersuffix = 'provider', path = [], carregedModules = new Hashmap ([], true), // pré-configure $ fornece o serviço de chamada de chamadas em serviço de serviço: fábrica de fábricas, etc. SupportObject (Value), Constant: SupportObject (Constant), Decorator: Decorator}}, // ProviderInjector, Instância Injetor Dois injetores // Instância do Injetor fornece serviço e outras injeções externamente, e o provider) fornece um provedor internamente para obter o ProviderNjector = (ProviderCache. $ injectorminer ('UNN', "Provedor desconhecido: {0}", Path.Join ('<-')); Return InstânciaInjector.invoke (provedor. $ get, provedor, indefinido, nome de service); // Módulo de carregamento foreach (LoadModules (modulestoload), function (fn) {instanceInjector.invoke (fn || noop);}); retornar a instância dojector;}2. $ Fornecer
$ fornece: {provedor: supportObject (provedor), fábrica: supportObject (fábrica), serviço: supportObject (serviço), valor: supportObject (value), constante: supportObject (constante), decorador: decorador}2.1 SupportObject
Para métodos de embalagem, o método antes da embalagem aceita dois parâmetros (chave, valor). O método embalado pode suportar os parâmetros do objeto que passam, ou seja, várias chaves -> valores.
função supportObject (delegate) {return function (chave, value) {if (isobject (key)) {foreach (chave, reverseparams (delegado)); } else {return delegate (chave, valor); }};}2.2 Provedor
Revise como provedor, serviço e fábrica são usados
App.Factory ('ServiceName', function () {return {getName: function () {}, setName: function () {}}}); app.service ('serviceName', function () {this.getName = function () {} thissetName (function () {) {}); function ($ httpprovider) {// injete $ httpprovider this. $ get = function () {return {getName: function () {}, setName: function () {}}}; assertnothasownProperty (nome, 'serviço'); // 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 (! provider _. $ get) {tiro $ injectorminer ('pget', "provider '{0}' deve definir $ get método de fábrica.", nome); } retornar provercache [nome + provendersuffix] = provedor _;} função factory (nome, factoryfn) {reportar provedor (nome, {$ get: factoryfn}); } função serviço (nome, construtor) {retornar fábrica (nome, ['$ injetor', função ($ injector) {return $ injector.instantiate (construtor);}]);} Valor da função (nome, val) {retornar fábrica (nome, valuefn (val)); }Finalmente resumido para a implementação do provedor, cache o provedor do provedorcache para chamada
O que é diferente dos outros é a implementação da constante, que é salva no ProviderCache e Instancecache, respectivamente, para que o provedor e o serviço possam ser injetados.
função constante (nome, valor) {assertnoThasownProperty (nome, 'constante'); provercache [nome] = value; Instancecache [nome] = value;}2.3 Revise os módulos de carga
função runinvokequeue (fila) {var i, ii; for (i = 0, ii = fila.length; i <ii; i ++) {var InvoKeargs = fila [i], provider = providerInjector.get (InvoKeargs [0]); // O formato da fila é armazenado em [$ fornece, fábrica, argumentos] // Após a substituição, $ fornece.Factory.Apply ($ fornece, argumentos); // é para chamar $ provid Factory, Service e outros provedores [InvoKeargs [1]]. Aplicar (provedor, InvoKeargs [2]); }}2.4 Decorador
Exemplo:
Module.config (function ($ fornece) {$ fornece.Decorator ('Mail', function ($ delegate) {$ delegate.addcc = function (cc) {this.cc.push (cc);}; retorna $ delegate;});})Usando o exemplo, pode-se ver que o parâmetro aprovado $ delegate é a instância de serviço original e você precisa adicionar um método a essa instância, que é o chamado decorador
Código -fonte:
Decorador de funções (nome do serviceName, decorfn) {var origin -provider = providerInjector.get (serviceName + providersuffix), origem $ get = origem. $ get; origem. $ get = function () {// gera a instância de serviço necessária através do provedor obtido acima e injete -o na lista de parâmetros com $ delegate var originstrance = instanceInjector.invoke (origem get, origem); Retornar Instância de InstânciaInjector.invoke (decorfn, null, {$ delegate: OriginStance}); };}3. CreateInternalInjector
3.1 Estrutura geral
// Obtenha -o do cache, se não, ligue para a fábrica para criá -lo. Veja a análise GetService para obter detalhes
Função CreateInternalInjector (cache, fábrica) {função getService (serviceName) {} função Invoke (fn, self, habitantes locais, serviceName) {} função instantiate (tipo, local, // instantalize) {} return {// Execute fn, Invoke: invoke, // instantize fn) {} // Obtenha a lista de parâmetros do método de anotação de injeção: anote, // Confirme se ele contém provedor ou serviço possui: function (nome) {return providercache.hasownproperty (nome + provendersuffix) || Cache.HasownProperty (nome); }};}3.2 Anotar
Obtenha a lista de parâmetros de FN
// tipo1Function fn (a, b, c) -> ['a', 'b', 'c'] // type2 ['a', 'b', fn] -> ['a', 'b'] // type3function fn () {} fn.Código -fonte:
Função AnoTate (fn, strictdi, nome) {var $ inject, fntext, argdecl, last; if (typeof fn === 'function') {if (! ($ inject = fn. $ inject)) {$ inject = []; if (fn.length) {// if (strictdi) {if (! Isstring (nome) ||! name) {name = fn.name || anonfn (fn); } arremesso $ injectorminer ('strictdi', '{0} não está usando anotação explícita e não pode ser invocada em modo rigoroso', nome); } // Remova o comentário fntext = fn.toString (). Substitua (Strip_comments, ''); // Selecione todos os parâmetros fn (a, b, c, d) -> 'a, b, c, d' argdecl = fntext.match (fn_args); // dividido em matriz foreach (argdecl [1] .split (fn_arg_split), function (arg) {arg.replace (fn_arg, function (all, subscore, nome) {$ inject.push (name);});}); }); } fn. $ inject = $ inject; }} else if (isarray (fn)) {last = fn.length - 1; assertargfn (fn [last], 'fn'); $ inject = fn.slice (0, último); } else {asserttargfn (fn, 'fn', true); } retornar $ injetar;}3.3 GetService
// Quando não houver serviço no cache, digite mais, cache [serviceName] = instantando para fazer uma marca // porque a próxima chamada de fábrica (serviceName), na verdade é uma chamada recursiva // function (serviceName) {// var provider = providerinject.get (servIDERIDERSUFFix); serviceName); //} // InstanceInjector.invoke (provedor. $ get receberá os parâmetros que precisam ser injetados e injetar // Portanto, depois de marcá -lo, você pode determinar se existe uma função de dependência circular getService (serviceName) {if (cache. $ injetivo (err) {if (cache [nome do servidor] === Instantando) {exclua cache [nome do serviço];3.4 Invoque
função Invoke (fn, self, habitantes locais, serviceName) {if (typeof habitais === 'string') {serviceName = local; habitantes locais = nulo; } var args = [], // Obtenha a lista de parâmetros $ inject = anote (fn, strictdi, serviceName), comprimento, i, key; for (i = 0, comprimento = $ inject.length; i <comprimento; i ++) {key = $ inject [i]; if (typeof key! == 'string') {tiro $ injectorminer ('itkn', 'token de injeção incorreto! } // prioridade dos habitantes locais Args.push (habitantes locais && Locais.HasownProperty (chave)? } if (isarray (fn)) {fn = fn [comprimento]; } retornar fn.apply (self, args);}3.5 Instantados
função instantiate (type, moral, serviceName) {var construtor = functutor () {}, instância, retornedValue; // Quando o tipo é a matriz, obtenha o último parâmetro como: ['$ window', function ($ win) {}] construtor.prototype = (isarray (type)? Type [type.length - 1]: tipo) .prototipo; instância = new construtor (); // chama Invoke para executar o método de tipo ReturnEdValue = Invoke (Tipo, Instância, Locais, ServiceName); Retornar Isobject (ReturnValue) || ISFUNCTION (ReturnValue)? ReturnEdValue: Instância;}A função do instante é instanciar o tipo, e os parâmetros podem ser transmitidos automaticamente para o construtor durante o processo de instanciação.