AngularJS模組具體解釋

來源:互聯網
上載者:User

標籤:func   for   lan   debug   deb   inject   局部變數   led   argument   

模組是提供一些特殊服務的功能塊。比方本地化模組負責文字本地化,驗證模組負責資料驗證。一般來說,服務在模組內部,當我們須要某個服務的時候,是先把模組執行個體化。然後再調用模組的方法。

但Angular模組和我們通常理解的模組不一樣。Angular模組僅僅保留服務的聲明,服務的執行個體化是由服務注入器完畢的,執行個體化之後服務就留在了服務注入器中,和模組沒有關係了,這就是為什麼我們使用的服務全部來自注入器的原因。

每調用一次angular.boostrap()方法會建立一個新的Angular應用和一個新的服務注入器,因此。每一個應用都相應一個服務注入器。彼此互不衝突。

在angular中,模組能夠是對象、方法(假設是數組,數組的最後一個元素必須是方法。前面的元素都是方法按順序排列的參數名稱)。後面講的模組屬性和方法。都屬於通過angular.module()定義的模組對象。假設模組是方法。是不須要經過angular.module()定義的,僅僅需寫入依賴數組(就是說依賴數組的元素能夠是方法)。模組在載入依賴關係的時候直接運行了。

注意:通過angular.module()方法定義的模組是唯一的。假設反覆定義就會覆蓋前面的定義。

angular模組

angular模組通過angular.module(name,requires, configFn)方法產生:

  • 參數name是模組名稱。
  • 參數requires表示相依模組數組。

    假設不設定requires參數,調用angular.module(name)方法表示擷取這個模組;因此,假設確定新模組沒有依賴關係,必須設定requires為空白數組[];

  • 參數configFn是方法或數組。負責在模組初始化時做一些配置。假設是數組。最後一個元素必須是方法。

方法configFn並非在運行angular.module()的時候馬上運行,而是當這個模組被第一次使用時,由注入器調用運行。

同一時候,查看方法configFn中的this就會發現,這個this在瀏覽器中指向的是window。而不是module。並且,方法configFn僅僅會運行一次,因此同一個angular模組不會反覆配置。

參數requires中的字串表示依賴的模組名稱。假設不是字串。則必須是方法(或數組格式的方法),那麼。這種方法就代表了一個模組。

同名模組

已經初始化的angular模組儲存在一個叫modules的緩衝對象中,key是模組名,value是模組對象。所以。定義一個同名的模組,等於覆蓋之前的模組。

服務注入

前面已經講了,angular模組僅僅保留服務的定義,如今我們再來理解服務是怎樣加入注入器的。

在瞭解服務注入器前。還須要瞭解還有一個概念,就是服務提供者。在Angular中稱為Provider,差點兒全部的服務(除了$injector)都是由服務提供者供應。不管是服務還是服務提供者。他們在Angular中都是唯一的,服務和服務提供者是一個一對一的關係。也正是由於這個關係,我們在使用模組service()、value()等方法時,感覺我們定義的好像僅僅是服務,但事實上Angular背後為這些服務都建立了一一相應的服務提供者。注入器的機制就是當我們須要某個服務的時候,首先依據服務名找到相應的服務提供者。然後由服務提供者建立相應的服務並返回。

所以這就是整個過程:

  1.  模組定義服務、服務提供者。
  2.  注入器依據模組依賴關係載入模組,執行個體化全部服務提供者;
  3.  應用須要服務,注入器依據服務名尋找服務提供者。服務提供者執行個體化服務。

以上僅僅是理論。如今從代碼層面來看Angular是怎樣實現的。

每一個angular模組內建有三個數組。invokeQueue儲存怎樣注入服務提供者和值的資訊;configBlocks儲存模組的配置資訊。runBlocks儲存這個模組的運行資訊。

模組被使用的時候,注入器依據invokeQueue中的資訊。執行個體化服務提供者;依據configBlocks中的資訊對服務提供者做一些額外的處理;依據runBlocks中提供的資訊,調用前面的服務提供者提供的服務運行模組須要完畢的工作。


angular模組提供了非常多方法來填充這三個數組,比方config()、run()等。三個數組的元素也是數組。詳細元素格式參考後面的說明。


調用隊列 – invokeQueue

數組元素為[‘provider’, ‘method’, arguments]。

舉例– 加入一個Controller:

angular.module(‘ngAppDemo‘,[]).controller(‘ngAppDemoController‘,function($scope) {      $scope.a= 1;      $scope.b = 2;});

這段代碼等於:

invokeQueue.push([‘$controllerProvider‘,‘register‘, [‘ngAppDemoController‘, function(){}]]);

注入器依據這個資訊,就會調用$controllerProvider的register方法注冊一個ngAppDemoController。

配置隊列 – configBlocks

元素格式為[‘$injector‘, ‘invoke‘, arguments]。

運行隊列 – runBlocks

元素要求是方法,或者是數組。數組最後一個元素是方法。

angular模組執行個體屬性和方法屬性requires

表示模組的依賴數組。即angular.module方法的requires參數。

name

模組的名字。

_invokeQueue、_configBlocks、_runBlocks

分別相應invokeQueue、configBlocks、runBlocks。

方法

模組的下面方法最後全部會返回模組執行個體本身,形成運行鏈

animation()

調用這種方法表示這個模組將在$animateProvider中注冊一個動畫服務。

原理:在invokeQueue尾部插入[‘$animateProvider‘, ‘register‘, arguments]。

config()

調用這種方法,表示給這個模組追加一個配置方法。

原理:在configBlocks尾部插入[‘$injector‘,‘invoke‘, arguments]。

constant()

調用這種方法表示這個模組將給預設的$provider注冊一個常量。

原理:在invokeQueue首部插入[‘$provide‘, ‘constant‘, arguments]。

controller()

調用這種方法表示模組將在$controllerProvider中注冊一個控制器。

原理:在invokeQueue尾部插入[‘$controllerProvider‘, ‘register‘, arguments]。

directive()

調用這種方法表示這個模組將在$compileProvider中注冊一個指令。

原理:在invokeQueue尾部插入[‘$compileProvider‘, ‘directive‘, arguments]。

factory()

調用這種方法表示這個模組中將產生一個服務工廠(隱式建立一個了服務提供者)。

原理:在invokeQueue尾部插入[‘$provide‘, ‘factory‘, arguments]。

filter()

調用這種方法表示這個模組將在$filterProvider中注冊一個過濾器。

原理:在invokeQueue尾部插入[‘$filterProvider‘, ‘register‘, arguments]。

provider()

調用這種方法表示這個模組將加入一個服務提供者。

原理:在invokeQueue尾部插入[‘$provide‘, ‘provider‘, arguments]。

run(block)

調用這種方法表示這個模組將運行某個功能塊。block能夠是方法,也能夠是數組。

原理:在invokeQueue尾部插入block。

service()

調用這種方法表示這個模組將注冊一個服務(隱式建立了一個服務提供者)。

原理:在invokeQueue尾部插入[‘$provide‘, ‘service‘, arguments]。

value()

調用這種方法表示這個模組將注冊一個變數(隱式建立了一個服務提供者)。

原理:在invokeQueue尾部插入[‘$provide‘, ‘value‘, arguments]。

服務注入器(Service Injector) & 服務提供者(Service Provider)

在Angular中,服務可能是對象、方法、或者一個常量值。服務由服務提供者建立。而服務提供者由注入器統一管理。當我們須要某個服務的時候。注入器負責依據服務名尋找相應的服務提供者,然後由服務提供者的$get()生產工廠建立服務執行個體。因此。服務提供者必須有一個$get()方法,這種方法就是服務建立單例工廠。

背後原理:注入器中的Providers和Services各自通過一個Map對象儲存在緩衝(分別相應providerCache和instanceCache)中,僅僅只是Providers的key是serviceName + “Provider”,而Services的key是serviceName。

服務提供者-Provider

Provider即服務提供者,必須有一個$get()方法。$get()的傳回值是Provider在注入器中實際的服務。

注入器

建立注入器的方法僅僅在bootstrap()方法中被調用過,也就是說,每一個angular應用相應一個注入器。

注入過程

注入器由angular.injector(modulesToLoad, isStrictDi)方法建立。在angular中事實上為createInjector方法。參數modulesToLoad是數組,元素格式為下面之中的一個:

  • ‘module’,模組的名稱。
  • [‘service1’, ‘service2’, fn]。
  • fn,方法的傳回值必須仍然是方法。

方法angular.injector()的運行過程:

1.        遍曆modulesToLoad。依據moduleName尋找或產生相應的模組。

2.        調用模組invokeQueue中的全部方法。這一步的目的是建立必需的服務。

3.        調用模組configBlocks中的全部方法,目的是用已有的服務配置這個模組。

4.        調用注入器的invoke()方法運行模組runBlocks的全部方法。

5.        返回服務注入器執行個體。

不是全部模組都是對象,假設模組本身是方法或者是數組(最後一個元素必須是方法)。則運行這種方法、或數組的最後一個方法,相當於直接進入了第四步。

注入器與bootstrap的關係

建立注入器的方法在angular.js中僅僅在bootstrap()方法中被調用過。也就是說,每一個angular應用相應一個注入器。

注入器方法

在providerCache中和instanceCache中分別內建有一個$injector對象,分別負責給模組注入服務提供者和為方法注入服務。

一般我們僅僅談論instanceCache中的$injector對象。由於providerCache和它的$injector是私人的,僅僅在Angular內部代碼使用。

比方,運行模組調用隊列、配置隊列中的方法時注入的是服務提供者,而當調用運行隊列中的方法時,注入的是服務。

$injector.invoke(fn, self, locals, serviceName)

運行方法fn。

locals是可選參數,是對象,表示局部變數。

self是fn中的this。

最後一個參數serviceName是可選參數,表示在哪個服務中調用了fn方法,用於錯誤資訊顯示,沒有處理邏輯。

$injector.instantiate(Type, locals, serviceName)

l  假設參數Type為方法,依據Type的prototype建立一個執行個體(通過Object.create方法建立),假設Type是數組。使用最後一個元素的prototype。

l  參數Locals是當Type方法的參數出如今locals對象中的時候。取locals[arg]的值又一次作為Type的參數。假設locals中沒有。則等價於調用get(arg,serviceName)擷取service作為新的參數。

執行個體化過程能夠簡單概括為

Type.apply(Object.create(Type.prototype),locals[argName]|| get(argName, serviceName))。

注意:執行個體化出來的不一定是對象。也可能是方法。

最後一個參數serviceName是可選參數,表示在哪個服務中執行個體化了Type,用於錯誤資訊顯示,沒有處理邏輯。

$injector.get(name, caller)

從注入器中擷取一個服務執行個體。

參數name是服務的名稱。參數caller也是字串,表示調用這個服務的是哪個方法,用於錯誤資訊提示。沒有處理邏輯。

$injector.annotate(fn[,strictDi][,name] )

返回數組。數組的元素是fn方法須要注入的依賴服務。

在strict 模式下,方法的依賴注入必須使用顯示的註解加入,也就是說通過fn.$injector能夠擷取這種方法的依賴注入。

參數name是可選的,用於錯誤顯示,沒有處理邏輯。

方法annotate()也能夠接受數組,數組的最後一個參數一定是fn,前面的元素則是依賴。

$injector.has(name)

檢查該注入器中是否存在指定的服務。

Provider方法

注入器的providerCache中內建有一個$provider對象,這是注入器的預設服務提供者,$provider有六個固定的方法。這幾個方法的作用主要是為注入器加入其他服務提供者。

注意:

  • 下面全部方法的name參數不須要以“Provider”結尾,由於provider()方法會預設把這個尾碼加上。

  • 下面不論什麼一個方法不做同名推斷,因此,假設出現同名,後者將覆蓋前者。

$provider.provide(name, provider)

參數provider能夠是方法或數組,也能夠是對象。

l  假設是方法,則是provider的建構函式。

調用注入器的instantiate()方法,產生一個provider執行個體。並以name為key儲存在注入器的providerCache中。

l  假設是數組。最後一個必須是provider的建構函式。前面的就是建構函式的參數名。之後的原理和provider是方法的情形同樣。

l  假設是對象,說明這個provider已經被執行個體化了,僅僅需有$get()方法就可以。

$provider.factory(name, factoryFn, enforce)

使用$provider.provide()一般須要定義一個Provider類,假設不想定義Provider類,而是直接定義服務工廠。就能夠使用這種方法。

背後原理:首先產生一個匿名對象,這個對象的$get屬性就是factoryFn(enforce為false的情況下),然後把這個匿名對象作為$provider.provide()方法的第二個參數。所以。factoryFn事實上依舊是綁定在一個provider上的。

$provider.service(name, constructor)

調用injector.instantiate()方法,利用參數constructor產生service執行個體,參數name是這個service的名稱。

眾所周知,service由provider提供,那這種方法是怎麼回事?原理:Angular首先依據constructor產生一個factoryFn,然後調用$provider.factory(name, factoryFn)。

所以事實上還是產生了一個provider。

舉例:

$provider.service(‘filter‘, constructor)

等於建立了一個filter服務執行個體。並且在providerCache中儲存了一個名稱為“filterProvider”的服務提供者。

      

$provider.value(name, value)

這種方法實際調用injector.factory(name,valueFn(value), false)方法實現。所以事實上等於建立一個僅僅提供值的服務提供者。

$provider.constant(name, value)

這種方法直接在providerCache中加入一個屬性實現。

$provider.decorate(serviceName, decorFn)

改動舊的服務,改為運行decorFn方法,並把servcieName原來的服務作為一個參數。參數名為$delegate。等價於一個靜態代理。

背後原理:首先依據seviceName找到Provider,然後改動provider的$get屬性。

服務執行個體化

全部服務都由Provider管理,除了常量值,其他一般都是還沒有建立出來的。

瞭解了注入器的全部方法。也應該能夠看出,僅僅有兩個方法:get()和invoke()真實的調用了服務。

事實上,服務的執行個體化實際是在注入器的get()方法中完畢的。而invoke()僅僅是在須要的時候調用了get()。

angular內建模組ngLocale - 本地化模組

angular.module(‘ngLocale‘,[]).provider(‘$locale‘, $LocaleProvider);

結果是invokeQueue.push([‘$provide‘, ‘provider‘,[‘$locale‘, $LocaleProvider]]);

ng

angular.module(‘ng‘,[‘ngLocale‘]).config([‘$provide‘, function(){}]);

結果是configBlocks.push([‘$injector‘, ‘invoke‘,[‘$provide‘, function(){}]])。

三個固定模組

每一個使用bootstrap(element, modules, config)產生的應用,注入器中有三個固定的模組:

  • 第一個模組是"ng"。
  • 第二個模組是[‘$provider’,fn],它的作用是把根項目element作為變數儲存在$provider中。

  • 第三個模組是[‘$compileProvider’,fn],它的作用是依據config.debugInfoEnabled調用 $conpileProvider.debugInfoEnabled(true)。

AngularJS模組具體解釋

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

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.