公司一些管理后台的前端页面,使用的是angular开发的,得益于angular的双向绑定和模块化controller使得构建pc端的CRUD应用简单了不少。angular有很多比较难理解的概念,上手起来没有vue简单,不过对着模板项目、看看tutorial、阅读项目代码再仿照项目代码写一些业务功能还是可行的。如果想要用到一些高级功能那就要下一定功夫学习才行。

遇到的问题

在开发的时候遇到了这么一个问题,先上代码

'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的文档来找找原因。

constant和run是什么

angular比较核心的一个概念就是依赖注入,angular的模块化以及模块间的依赖管理都是基于此的。而这些依赖都是从哪里来的或者怎么自建一些依赖呢?这就需要自己定义一些Providers,angular提供了5种Provider recipe(恕我不知道怎么翻译这个概念):factory、service、value、constant、provider,这里我们只关心constant。官方文档描述constant是用来为配置阶段(config phase)和运行阶段(run phase)提供没有依赖的简单对象,也就是说我们在constant里面定义的对象或基本类型可以在run和config里面注入:

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  
 })

那什么是运行和配置阶段呢?官方文档这样说:

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.

上面介绍angular的模块实际上是配置块和运行块的集合,这些blocks是在angular的启动(bootstrap)过程中被添加进模块的。Configuration blocks和Run blocks可以理解为队列,一个模块可以写多个.run和.config,最后被依次添加进相应的blocks中。config只能注入provider 和constant recipe,run只能注入实例(不是providers)和constant recipe。但我测试value recipe是可以注入到run的,好吧我承认angular文档真的不好理解。

总之我觉得就一句话概况就是:constant可以理解为是angular用来为模块提供可注入的所有模块共享的常量(无依赖的简单对象或类型),并且在config和run阶段之前定义好的。 (仅仅是个人理解)

执行顺序

上面说了constant应该是在run之前被执行,可这只是程序运行的表象,为什么会这样呢,于是就搜索了一下angular的启动过程,其中这篇对启动过程的[源码分析](http://liuwanlin.info/angular...),给了我一些启发。
里面介绍了setupModuleLoader方法,该函数返回了一系列的API,用于Angular组织模块,注册指令、服务、控制器。

能够看到刚才前面介绍的configBlocks和runBlocks,这里要说明的是constant使用了unshift,将constant插入到队列的首部,这也就保证了constant在配置、运行之前能够在其他所有块中被注入。

再看下loadModules方法,这个方法用于加载模块,即返回需要运行的块,之前提到的constant和provider其实就是被加入了invokequeue之中,这只是注册并没有执行,在这个函数中调用runInovequeue才真正执行生成实例,也可以看出config是在run之前运行的:

解决问题

上面大致解释了一下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',//项目中请求服务端异步获取数据的接口
 }

参考文档:

angular providers
angular modular
dependency injection
AngularJS中几种Providers(Factory,Service,Provider)的区别
AngularJS源码阅读1:启动过程

angular开发中问题记录--启动过程初探的更多相关文章

  1. html5录音功能实战示例

    这篇文章主要介绍了html5录音功能实战示例的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  2. 基于 HTML5 WebGL 实现的医疗物流系统

    物联网( IoT ),简单的理解就是物体之间通过互联网进行链接。这篇文章给大家介绍基于 HTML5 WebGL 实现的医疗物流系统,感兴趣的朋友跟随小编一起看看吧

  3. HTML5页面无缝闪开的问题及解决方案

    这篇文章主要介绍了HTML5页面无缝闪开方案,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  4. HTML5跳转小程序wx-open-launch-weapp的示例代码

    这篇文章主要介绍了HTML5跳转小程序wx-open-launch-weapp的相关知识,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  5. ios – 尝试向我们分配IP而不是localhost或home时,NSURLSession失败

    我有一台本地运行的服务器(我的IP是192.168.0.98),并且已经尝试使用一些网络代码来访问它.最初这是通过AFNetworking完成的,但我现在用这样的NSURLSession完成了它:然后我用这3个URL运行它:>http://localhost:8080/api–>作品.>http://127.0.0.1:8080/api–>作品.>http://192.168.0.98:8080/

  6. ios – 与Xcode Bots持续集成

    我想使用Xcode机器人进行持续集成.我已经安装了OSXMavericks和Server(版本3).我可以使用Xcode5.0.1创建机器人.在集成时,它正在成功地执行分析测试,但总是最终的集成结果是失败的.IntegrationFailed.Unexpectedinternalservererror.Seetheintegration’slogsformoredetails.`我没有从服务器错误

  7. ios – Swift:不符合协议NSCoding

    我正在尝试在swift中使用NSCoding协议,但是似乎无法弄清楚为什么编译器会抱怨当我实现所需的方法时它“不符合协议NSCoding”:这是一个bug还是我只是想念一些东西?解决方法在报告导航器中的详细编译器消息中可以看到,您的方法未正确声明:此外,initWithCoder方法必须标记为必需:在Swift3中,所需的方法是

  8. ios – 使用NSURLSession.downloadTaskWithURL时的内存泄漏

    或者,繁荣,内存泄漏.Apple的NSURLSession类参考在管理边框中的会话部分中指定:IMPORTANT—Thesessionobjectkeepsastrongreferencetothedelegateuntilyourappexitsorexplicitlyinvalidatesthesession.Ifyoudonotinvalidatethesession,yourappleaksmemoryuntilitexits.嗯是的.你也可以考虑这两种方法:>flushWithCompletio

  9. xcode – osx上的config.log是什么?它在哪里?

    任何人都可以解释’configure’是什么和做什么,一般可以找到config.log文件?

  10. ios – Swift Physics:碰撞时的角度计算错误

    我有一个简单的SpriteKit应用程序,带有墙壁和球.两者都设置了SKPhysicsBody.当我向一个方向施加力时,我希望球在碰撞时以相同的角度在墙壁上反射,但方向相反.但有时我看到角度很奇怪.我使用了所有的physicsBody属性,但是无法修复它.有时第一次反射看起来很好,但是第三次或第六次反射,有时第一次反射是错误的角度.我从不同的帖子中读到,人们有点自我计算的“正确方向”.但我无法想象

随机推荐

  1. Angular2 innerHtml删除样式

    我正在使用innerHtml并在我的cms中设置html,响应似乎没问题,如果我这样打印:{{poi.content}}它给了我正确的内容:``但是当我使用[innerHtml]=“poi.content”时,它会给我这个html:当我使用[innerHtml]时,有谁知道为什么它会剥离我的样式Angular2清理动态添加的HTML,样式,……

  2. 为Angular根组件/模块指定@Input()参数

    我有3个根组件,由根AppModule引导.你如何为其中一个组件指定@input()参数?也不由AppModalComponent获取:它是未定义的.据我所知,你不能将@input()传递给bootstraped组件.但您可以使用其他方法来做到这一点–将值作为属性传递.index.html:app.component.ts:

  3. angular-ui-bootstrap – 如何为angular ui-bootstrap tabs指令指定href参数

    我正在使用角度ui-bootstrap库,但我不知道如何为每个选项卡指定自定义href.在角度ui-bootstrap文档中,指定了一个可选参数select(),但我不知道如何使用它来自定义每个选项卡的链接另一种重新定义问题的方法是如何使用带有角度ui-bootstrap选项卡的路由我希望现在还不算太晚,但我今天遇到了同样的问题.你可以通过以下方式实现:1)在控制器中定义选项卡href:2)声明一个函数来改变控制器中的散列:3)使用以下标记:我不确定这是否是最好的方法,我很乐意听取别人的意见.

  4. 离子框架 – 标签内部的ng-click不起作用

    >为什么标签标签内的按钮不起作用?>但是标签外的按钮(登陆)工作正常,为什么?>请帮我解决这个问题.我需要在点击时做出回复按钮workingdemo解决方案就是不要为物品使用标签.而只是使用divHTML

  5. Angular 2:将值传递给路由数据解析

    我正在尝试编写一个DataResolver服务,允许Angular2路由器在初始化组件之前预加载数据.解析器需要调用不同的API端点来获取适合于正在加载的路由的数据.我正在构建一个通用解析器,而不是为我的许多组件中的每个组件设置一个解析器.因此,我想在路由定义中传递指向正确端点的自定义输入.例如,考虑以下路线:app.routes.ts在第一个实例中,解析器需要调用/path/to/resourc

  6. angularjs – 解释ngModel管道,解析器,格式化程序,viewChangeListeners和$watchers的顺序

    换句话说:如果在模型更新之前触发了“ng-change”,我可以理解,但是我很难理解在更新模型之后以及在完成填充更改之前触发函数绑定属性.如果您读到这里:祝贺并感谢您的耐心等待!

  7. 角度5模板形式检测形式有效性状态的变化

    为了拥有一个可以监听其包含的表单的有效性状态的变化的组件并执行某些组件的方法,是reactiveforms的方法吗?

  8. Angular 2 CSV文件下载

    我在springboot应用程序中有我的后端,从那里我返回一个.csv文件WheniamhittingtheURLinbrowsercsvfileisgettingdownloaded.现在我试图从我的角度2应用程序中点击此URL,代码是这样的:零件:服务:我正在下载文件,但它像ActuallyitshouldbeBook.csv请指导我缺少的东西.有一种解决方法,但您需要创建一个页面上的元

  9. angularjs – Angular UI-Grid:过滤后如何获取总项数

    提前致谢:)你应该避免使用jQuery并与API进行交互.首先需要在网格创建事件中保存对API的引用.您应该已经知道总行数.您可以使用以下命令获取可见/已过滤行数:要么您可以使用以下命令获取所选行的数量:

  10. angularjs – 迁移gulp进程以包含typescript

    或者我应该使用tsc作为我的主要构建工具,让它解决依赖关系,创建映射文件并制作捆绑包?

返回
顶部