公司一些管理後臺的前端頁面,使用的是angular開發的,得益於angular的雙向綁定和模塊化controller使得構建pc端的CRUD應用簡單了很多。angular有不少比較難理解的概念,上手起來沒有vue簡單,不過對着模板項目、看看tutorial、閱讀項目代碼再仿照項目代碼寫一些業務功能仍是可行的。若是想要用到一些高級功能那就要下必定功夫學習才行。javascript
在開發的時候遇到了這麼一個問題,先上代碼html
'use strict'; var domain = 'http://localhost:1337'; //開發環境下的服務端地址, var MY_DOMAIN = 'http://production.com'; // 生成環境的網站地址 angular.module('adminApp').run(function($location) { if ($location.host() !== 'localhost') { domain = MY_DOMAIN; } }) .constant('myConfig', { host: domain, domain: domain, api: this.domain + '/admin', //項目中請求服務端異步獲取數據的接口 }
上面的代碼,乍一看是自動切換生產和開發環境的服務端地址,但是當部署以後發現這段代碼好像並無生效,domain始終是'http://localhost:1337',並無經過判斷host而被賦值爲MY_DOMAIN。
在沒有對angular的運行機制有所瞭解的狀況下,我會認爲代碼會自上而下的執行,這樣在.constant的代碼執行以前,會先執行.run裏面的方法。然而代碼的最終執行結果代表,.constant內的代碼運行應該是先於.run裏面的代碼。因而閱讀angular的文檔來找找緣由。前端
angular比較核心的一個概念就是依賴注入,angular的模塊化以及模塊間的依賴管理都是基於此的。而這些依賴都是從哪裏來的或者怎麼自建一些依賴呢?這就須要本身定義一些Providers,angular提供了5種Provider recipe(恕我不知道怎麼翻譯這個概念):factory、service、value、constant、provider,這裏咱們只關心constant。官方文檔描述constant是用來爲配置階段(config phase)和運行階段(run phase)提供沒有依賴的簡單對象,也就是說咱們在constant裏面定義的對象或基本類型能夠在run和config裏面注入:vue
angular.module('adminApp') .constant('myObj', { name: 'angular' }) .constant('myStr', 'hello') .config(function(myObj) { console.log(myObj.name) // angular }) .run(function(myStr) { console.log(myStr) //hello })
那什麼是運行和配置階段呢?官方文檔這樣說:java
A module is a collection of configuration and run blocks which get applied to the application during the bootstrap process. In its simplest form the module consists of a collection of two kinds of blocks:
1.Configuration blocks - get executed during the provider registrations and configuration phase. Only providers and constants can be injected into configuration blocks. This is to prevent accidental instantiation of services before they have been fully configured.
2.Run blocks - get executed after the injector is created and are used to kickstart the application. Only instances and constants can be injected into run blocks. This is to prevent further system configuration during application run time.angularjs
上面介紹angular的模塊其實是配置塊和運行塊的集合,這些blocks是在angular的啓動(bootstrap)過程當中被添加進模塊的。Configuration blocks和Run blocks能夠理解爲隊列,一個模塊能夠寫多個.run和.config,最後被依次添加進相應的blocks中。config只能注入provider 和constant recipe,run只能注入實例(不是providers)和constant recipe。但我測試value recipe是能夠注入到run的,好吧我認可angular文檔真的很差理解。bootstrap
總之我以爲就一句話概況就是:constant能夠理解爲是angular用來爲模塊提供可注入的全部模塊共享的常量(無依賴的簡單對象或類型),而且在config和run階段以前定義好的。 (僅僅是我的理解)api
上面說了constant應該是在run以前被執行,可這只是程序運行的表象,爲何會這樣呢,因而就搜索了一下angular的啓動過程,其中這篇對啓動過程的[源碼分析](http://liuwanlin.info/angular...),給了我一些啓發。
裏面介紹了setupModuleLoader方法,該函數返回了一系列的API,用於Angular組織模塊,註冊指令、服務、控制器。
可以看到剛纔前面介紹的configBlocks和runBlocks,這裏要說明的是constant使用了unshift,將constant插入到隊列的首部,這也就保證了constant在配置、運行以前可以在其餘全部塊中被注入。app
再看下loadModules方法,這個方法用於加載模塊,即返回須要運行的塊,以前提到的constant和provider其實就是被加入了invokequeue之中,這只是註冊並無執行,在這個函數中調用runInovequeue才真正執行生成實例,也能夠看出config是在run以前運行的:dom
上面大體解釋了一下constant先於run被執行的緣由,這也是文章最開始寫的代碼沒有按照預期執行的緣由。知道了緣由又知道.run裏面能夠注入已經定義的constant,那麼咱們就知道只要稍微改一下代碼就能夠獲得想要的結果:
'use strict'; var domain = 'http://localhost:1337'; //開發環境下的服務端地址, var MY_DOMAIN = 'http://production.com'; // 生成環境的網站地址 angular.module('adminApp').run(function($location, myConfig) { if ($location.host() !== 'localhost') { myConfig.domain = MY_DOMAIN; myConfig.api = myConfig.domain + '/admin'; //這裏不要指望myConfig裏面的domain會跟隨者domain變量的變化而變化,對象一旦創建,它的屬性值就是固定的了,想修改只能經過對象訪問屬性修改。 } }) .constant('myConfig', { host: domain, domain: domain, api: this.domain + '/admin', //項目中請求服務端異步獲取數據的接口 }
angular providers
angular modular
dependency injection
AngularJS中幾種Providers(Factory, Service, Provider)的區別
AngularJS源碼閱讀1:啓動過程