مقدمة
يتم استخدام الحاقن لأداء حقن المعلمة التلقائي ، على سبيل المثال
الدالة fn ($ http ، نطاق $ ، aservice) {}عند تشغيل NG ، HTTP $ ، نطاق $ ، سيتم تمرير Aservice تلقائيًا كمعلمات للتنفيذ.
من السهل في الواقع اكتشاف ذلك ، فعل الحاقن شيئين
يحلل رمز المصدر التالي كيفية تنفيذ شيئين أعلاه.
بناء
createInjector -> createInternalInjector return: instanceInjector
لذا ، فإن CreateInjector () إرجاع مثيل ، الهيكل كما يلي:
{invoke: invoke ، instantiate: instantiate ، get: getService ، anotate: anotate ، has: function (name) {return providercache.hasownproperty (name + providersuffix) || cache.hasownproperty (الاسم) ؛ }}تحليل رمز المصدر
1. إنشاء
وظيفة createInjector (modulestoload ، strictdi) {StrictDi = (StrictDi === True) ؛ var instantiAting = {} ، Providersuffix = 'Provider' ، path = [] ، loadedModules = new hashmap ([] ، true) ، SupportObject (value) ، ثابت: SupportObject (ثابت) ، ديكور: ديكور}} ، // ProviderInjector ، مثيل اثنين من الحقن // extominjector يوفر الخدمة وغيرها من الحقن من الخارج ، ويوفر ProviderInjector مزودًا داخليًا للوصول إلى الموفر = (providercache. $ enjector = createInteralInor "مزود غير معروف: {0}" ، path.join ('<-')) ؛ extrector.invoke (مزود. $ get ، مزود ، غير محدد ، servicename) ؛ // وحدة التحميل foreach (loadmodules (modulestoload) ، function (fn) {extalInjector.invoke (fn || noop) ؛}) ؛ إرجاع مثيل ؛}2. $ توفير
$ توفير: {Provider: SupportObject (مزود) ، المصنع: SupportObject (المصنع) ، الخدمة: SupportObject (الخدمة) ، القيمة: SupportObject (القيمة) ، ثابت: SupportObject (ثابت) ، ديكور: ديكور}2.1 SupportObject
بالنسبة لطرق التغليف ، تقبل الطريقة قبل التغليف معلمتين (مفتاح ، القيمة). يمكن أن تدعم الطريقة المعبأة معلمات الكائن التي تمر ، أي مفاتيح متعددة -> قيم.
دالة SupportObject (DepeGate) {return function (key ، value) {if (isObject (key)) {foreach (key ، reversparams (depigate)) ؛ } آخر {إرجاع مندوب (مفتاح ، قيمة) ؛ }} ؛}2.2 مزود
راجع كيفية استخدام المزود والخدمة والمصنع
App.Factory ('servicename' ، function () {return {getName: function () {} ، setName: function () {}}}) ؛ app.service ('servicename' ، function () {this.getName = function () {} this.setname = function ()} الدالة ($ httpprovider) {// use $ httpprovider this. $ get = function () {getName: function () {} ، setName: function () {}} AssertNothasOwnProperty (اسم ، "الخدمة") ؛ // عندما يكون Provider_ FN أو Array ، يمكن حقن مقدمي الخدمات الآخرين في معلمات // لأنه عندما يمكن نقل ProviderInjector.instantateate (Provider_) إلى مقدمي الخدمات الآخرين الذين يعتمدون على // هذا هو أيضًا الفرق بين المزود والخدمة والخدمات المصنع إذا (IsFunction_) | } if (! Provider _. $ get) {throw $ enjectorminerr ('pget' ، "Provider '{0}' يجب تحديد طريقة المصنع $." ، الاسم) ؛ } return ProviderCache [name + Providersuffix] = Provider _ ؛} Function Factory (name ، factoryfn) {return provider (name ، {$ get: factoryfn}) ؛ } خدمة الوظائف (الاسم ، مُنشئ) {return factory (name ، ['$ enjector' ، function ($ enjector) {return $ enjector.instantiate (constructor) ؛}]) ؛} قيمة الوظيفة (الاسم ، val) {return factory (name ، valuefn (val)) ؛ }تم تلخيصها أخيرًا لتنفيذ المزود ، وقم بتخزين الموفر إلى ProviderCache للاتصال
ما يختلف عن الآخرين هو تنفيذ ثابت ، والذي يتم حفظه في ProviderCache و Instancecache على التوالي ، بحيث يمكن حقن كل من المزود والخدمة.
وظيفة ثابت (الاسم ، القيمة) {assertNothAsownProperty (الاسم ، 'ثابت') ؛ ProviderCache [name] = value ؛ Instancecache [name] = value ؛}2.3 مراجعة loadmodules
وظيفة runInvokequeue (قائمة الانتظار) {var i ، ii ؛ لـ (i = 0 ، ii = queue.length ؛ i <ii ؛ i ++) {var evokeargs = queue [i] ، provider = providerInjector.get (InvokeArgs [0]) ؛ // يتم تخزين تنسيق قائمة الانتظار في [$ proved ، factory ، enduces] // بعد الاستبدال ، $ provide.factory.apply ($ proving ، almitions) ؛ // هو استدعاء $ Provid Factory ، Service وغيرها من المزود [InvokeArgs [1]]. تطبيق (مزود ، InvokeArgs [2]) ؛ }}2.4 ديكور
مثال:
module.config (function ($ sevel) {$ prove.decorator ('mail' ، function ($ depate) {$ deved.addcc = function (cc) {this.cc.push (باستخدام المثال ، يمكن ملاحظة أن المعلمة التي تم تمريرها $ $ هي مثيل الخدمة الأصلية ، وتحتاج إلى إضافة طريقة إلى هذه المثيل ، وهو ما يسمى بالديكور
رمز المصدر:
دائرة الدالة (servicename ، decorfn) {var origprovider = providerInjector.get (Servicename + Providersuffix) ، Orig $ get = Origprovider. $ get ؛ OrigpRovider. $ get = function () {// إنشاء مثيل الخدمة المطلوبة من خلال المزود الذي تم الحصول عليه أعلاه ، وحقنه في قائمة المعلمات مع $ devigate var originStance = extorlyInjector.invoke (Orig $ get ، Origprovider) ؛ return مثيل extairInjector.invoke (concfn ، null ، {$ مندوب: OriginStance}) ؛ } ؛}3
3.1 الهيكل العام
// احصل عليه من ذاكرة التخزين المؤقت ، إن لم يكن ، اتصل على المصنع لإنشائه. انظر تحليل GetService للحصول على التفاصيل
وظيفة CreateInternalInjector (ذاكرة التخزين المؤقت ، المصنع) {وظيفة getService (servicename) {} استدعاء (fn ، الذات ، السكان المحليين ، servicename) {} وظيفة instantiate (النوع ، السكان المحليين ، servicename) // احصل على قائمة المعلمات لطريقة التعليقات الشرحية: التعليقات ، cache.hasownproperty (الاسم) ؛ }} ؛}3.2 شرح
احصل على قائمة المعلمات من FN
// type1function fn (a ، b ، c) -> ['a' ، 'b' ، 'c'] // type2 ['a' ، 'b' ، fn] -> ['a' ، 'b']
رمز المصدر:
شرح الدالة (FN ، Strictdi ، name) {var $ enject ، fntext ، argDecl ، last ؛ if (typeof fn === 'function') {if (! ($ enject = fn. $ enject)) {$ enject = [] ؛ if (fn.length) {// if (structdi) {if (! isString (name) ||! name) {name = fn.name || Anonfn (FN) ؛ } رمي $ enjectorminerr ('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) ، الدالة (arg) {arg.replace (fn_arg ، function (All ، Underscore ، name) {$ enject.push (name) ؛}) ؛}) ؛ }) ؛ } fn. $ enject = $ enject ؛ }} آخر إذا (isarray (fn)) {last = fn.length - 1 ؛ assertargfn (fn [last] ، 'fn') ؛ $ enject = fn.slice (0 ، last) ؛ } آخر {assertargfn (fn ، 'fn' ، true) ؛ } إرجاع $ enject ؛}3.3 GetService
// عندما لا تكون هناك خدمة في ذاكرة التخزين المؤقت ، أدخل آخر ، ذاكرة التخزين المؤقت [servicename] = إنشاء علامة على علامة // لأن مصنع الاتصال التالي (servicename) ، فهو في الواقع دعوة متكررة // وظيفة (servicename) {// var provider = providerinjector.get (servicename + مزودات) ؛ servicename) ؛ //} // extalInjector.invoke (مزود. $ enjectorminerr (cdep "،" التبعية الدائرية "، إرجاع ذاكرة التخزين المؤقت (err) {if (cache [servicename] === instantiaTing) {delete cache [servicename] ؛3.4 استدعاء
دالة استدعاء (fn ، الذات ، والسكان المحليين ، servicename) {if (typeof alsals === 'string') {serviceName = facals ؛ السكان المحليين = فارغ ؛ } var args = [] ، // احصل على قائمة المعلمة $ enject = incenotate (fn ، structdi ، servicename) ، length ، i ، key ؛ لـ (i = 0 ، length = $ enject.length ؛ i <length ؛ i ++) {key = $ enject [i] ؛ if (typeof key! == 'string') {throw $ enjectorminerr ('Itkn' ، 'uncart increated incection! اسم الخدمة المتوقعة كسلسلة ، حصلت على {0}' ، المفتاح) ؛ }. } if (isarray (fn)) {fn = fn [length] ؛ } إرجاع fn.apply (الذات ، args) ؛}3.5 مثيل
دالة instantiate (النوع ، السكان المحليين ، servicename) {var constructor = function () {} ، مثيل ، returnedValue ؛ // عندما يكون النوع صفيفًا ، احصل على المعلمة الأخيرة مثل: ['$ window' ، function ($ win) {}] constructor.prototype = (isarray (type)؟ type [type.length - 1]: type) .prototype ؛ مثيل = مُنشئ جديد () ؛ // استدعاء استدعاء لتنفيذ طريقة type returnedValue = invoke (النوع ، مثيل ، السكان المحليين ، servicename) ؛ إرجاع isObject (returnedValue) || isfunction (returnedValue)؟ ReturnedValue: مثيل ؛}تتمثل وظيفة Instantiate في إنشاء مثيل للنوع ، ويمكن تمرير المعلمات تلقائيًا إلى المُنشئ أثناء عملية التثبيت.