Введение
Инжектор используется для выполнения автоматического впрыска параметров, например,
Функция Fn ($ http, $ accope, aservice) {}Когда NG работает, $ http, $ scope, Aservice будет автоматически передаваться в качестве параметров для выполнения.
На самом деле это легко понять, инжектор сделал две вещи
В следующем исходном коде анализируется, как реализовать две выше.
структура
createInjector -> createInternalInjector return: instanceInjector
Таким образом, CreateInjector () возвращает экземпляры, структура заключается в следующем:
{invoke: invoke, instantiate: instantiate, get: getservice, аннотат: аннотат, есть: function (name) {return providercache.hasownproperty (имя + providersuffix) || cache.hasownproperty (имя); }}Анализ исходного кода
1. Createinject
Функция CreateInjector (ModuleStoLoad, strictdi) {strictdi = (strictdi === true); var instantiation = {}, providersuffix = 'поставщик', path = [], loadedmodules = new Hashmap ([], true), // pre-configure $ Предоставьте службу регистрации вызовов в LoadModules и т. д. ProviderCache = {$ предоставление: {Provider: SupportObject (Provider), Factory: SupportObject (Factory) SupportObject (значение), Constant: SupportObject (Constant), Decorator: Decorator}}, // Providerinject, ExactionInject, два инжектора // ExtanyInjecter предоставляет услуги и другие инъекции внешне, а ProviderInject обеспечивает поставщика для получения провайдера = (ProviderCache. $ injectorminerr ('inpl', "Неизвестный провайдер: {0}", path.join ('<-')); return exactionInject.invoke (поставщик. $ get, поставщик, не определен, ServiceName); // Модуль загрузки FOREACH (LOADMODULE (MODULESTOLOAD), FUNCTION (FN) {ExanceInInject.Invoke (fn || nOOP);}); вернуть экземпляры экземпляра;}2. $ Предоставлен
$ Предоставьте: {Provider: SupportObject (поставщик), Factory: SupportObject (Factory), Service: SupportObject (Service), значение: SupportObject (значение), Constant: SupportObject (Constant), Decorator: Decorator}2.1 поддержка
Для методов упаковки метод перед упаковкой принимает два параметра (ключ, значение). Метод упаковки может поддерживать проходящие параметры объекта, то есть несколько клавиш -> значения.
Функция поддержки objectObject (делегат) {return function (key, value) {if (isobject (key)) {foreach (key, reverseparams (делегат)); } else {return delegate (key, value); }};}2.2 поставщик
Просмотрите, как используются поставщики, обслуживание и завод
app.factory ('serviceName', function () {return {getName: function () {}, setName: function () {}}}); app.service ('serviceName', function () {this.getName = funct Функция ($ httpprovider) {// inject $ httpprovider this. $ get = function () {return {getName: function () {}, setName: function () {}}; Assertnothasownproperty (имя, «Сервис»); // Когда провайдер_ является fn или массивом, другие поставщики могут быть введены в параметры //, потому что, когда провайдер -дневник.instantiate (поставщик_) может передаваться другим поставщикам, которые зависят от // это также разница между провайдером и услугами и заводскими методами, если (isfunction (provider_) || } if (! Provider _. $ get) {throw $ injectorminerr ('pget', "Provider '{0}' должен определить $ get factory method.", name); } return ProviderCache [name + providersuffix] = Provider _;} Функциональная фабрика (имя, factoryfn) {return Provider (name, {$ get: factoryfn}); } Function Service (имя, конструктор) {return factory (name, ['$ Increjort', function ($ injector) {return $ injector.instantiate (constructor);}]);} Значение функции (имя, val) {return factory (name, valuefn (val)); }Наконец, суммировано для реализации поставщика, кэшируйте поставщика в ProviderCache для Call
Что отличается от других, так это реализация постоянной, которая сохраняется в ProviderCache и InstanceCache соответственно, чтобы как провайдер, так и услуга могли быть введены.
Функция константа (имя, значение) {assertnothasownproperty (name, 'constant'); ProviderCache [name] = value; Instancecache [name] = value;}2.3 Просмотрите LoadModules
функция runinvokequeue (queue) {var i, ii; for (i = 0, ii = queue.length; i <ii; i ++) {var invokeargs = queue [i], provider = providerinjector.get (invokeargs [0]); // Формат очереди хранится в [$ предоставление, фабрика, аргументы] // после замены, $ предоставьте. Factory.apply ($ предоставление, аргументы); // это должно позвонить по фабрике, обслуживанию и другим поставщикам, [vokeargs [1]]. Подать заявку (поставщик, indokeargs [2]); }}2.4 Декоратор
Пример:
module.config (function ($ предоставление) {$ предоставление.decorator ('mail', function ($ delegate) {$ delegate.addcc = function (cc) {this.cc.push (cc);}; return $ delegate;});})Используя пример, можно увидеть, что переданный параметр $ делегат является исходным экземпляром службы, и вам необходимо добавить метод в этот экземпляр, который является так называемым декоратором
Исходный код:
Функциональный декоратор (ServiceName, Decorfn) {var ouryProvider = ProviderInjector.get (ServicEName + ProviderSuffix), Orig $ get = ourprovider. $ get; OryProvider. $ get = function () {// генерировать необходимый экземпляр службы через поставщика, полученного выше, и введите его в список параметров с $ делегатом var ouringstance = exactionInjector.invoke (Orig $ get, ouryProvider); return exactioninjector.invoke (decorfn, null, {$ delegate: Originstance}); };}3. CreateInternalinjector
3.1 Общая структура
// Получите его из кеша, если нет, позвоните за фабрику, чтобы создать его. Подробнее см. Анализ GetService
Функция CreateInternalinjector (Cache, Factory) {function getService (ServiceName) {} Функция invoke (fn, self, локалы, ServiceName) {} Функциональный экземпляр // Получите список параметров метода аннотата впрыска: аннотировать, // подтвердить, содержит ли он поставщик или услуга: function (name) {return providercache.hasownproperty (имя + Providersuffix) || cache.hasownproperty (имя); }};}3.2 Аннотат
Получите список параметров FN
// функция типа1 Fn (A, B, C) -> ['A', 'B', 'C'] // type2 ['a', 'b', fn] -> ['a', 'b'] //функция type3 fn () {} fn. $ inject = ['a', 'c'] [>Исходный код:
Функция аннотата (fn, strictdi, name) {var $ inject, fntext, argdecl, last; if (typeof fn === 'function') {if (! ($ inject = fn. $ inject)) {$ inject = []; if (fn.length) {// if (strictdi) {if (! Isstring (name) ||! name) {name = fn.name || anonfn (fn); } бросить $ injectorminerr ('strictdi', '{0} не использует явную аннотацию и не может быть вызван в строгом режиме', имя); } // Удалить комментарий fntext = fn.toString (). Заменить (Strip_comments, ''); // Выберите все параметры fn (a, b, c, d) -> 'a, b, c, d' argdecl = fntext.match (fn_args); // разделить на массив Foreach (argdecl [1] .split (fn_arg_split), function (arg) {arg.replace (fn_arg, function (все, подчеркивание, имя) {$ 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
// Когда в кэше нет услуг, введите Else, Cache [ServiceName] = Instantiaing для создания Mark // Поскольку Fearly Call Factory (ServiceName), это фактически рекурсивная функция Call // (ServiceName) {// var provider = ProviderInject.get (ServicENAME + Providersuffix); ServiceName); //} // exactionInjector.invoke (поставщик. $ get выберет параметры, которые необходимо вводить и вводить // Следовательно, после маркировки, вы можете определить, существует ли функция циркулярной зависимости getService (serviceName) {if (cache.hashownproperty (serviceName) {if -servicemanate] indatemation) {if -servicemantay) {if -servicemantay) {if -servicemanate] = $ injectorminer ('cdep', «Обеспечение круговой зависимости: (err) {if (cache [ServiceName] ===3.4 Призыв
Функция invoke (fn, self, locals, serviceName) {if (typeof locals === 'string') {serviceName = locals; местные жители = null; } var args = [], // Получить список параметров $ inject = annotate (fn, strictdi, serviceName), длина, i, key; for (i = 0, length = $ inject.length; i <length; i ++) {key = $ inject [i]; if (typeof key! == 'string') {throw $ injectorminerr ('itkn', 'неправильный токен впрыска! Ожидаемое имя обслуживания как строка, at {0}', key); } // Приоритет местных жителей args.push (Locals && locals.hasownproperty (Key)? Mocals [Key]: getService (Key)); } if (isarray (fn)) {fn = fn [length]; } return fn.apply (self, args);}3,5 экземпляра
Функциональный экземпляр (тип, локалы, ServiceName) {var constructor = function () {}, экземпляр, returnedValue; // Когда тип массив, получите последний параметр, такой как: ['$ window', function ($ win) {}] constructor.prototype = (isarray (type)? Type [type.length - 1]: type) .prototype; encess = new Constructor (); // Вызовы Invoke, чтобы выполнить метод типа returnValue = invoke (type, экземпляр, местные жители, ServiceName); возврат isobject (returnValue) || isfunction (retendValue)? возвратФункция экземпляра заключается в создании экземпляра типа, а параметры могут быть автоматически переданы в конструктор в течение процесса экземпляра.