资讯专栏INFORMATION COLUMN

angular开发中问题记录--启动过程初探

G9YH / 1694人阅读

摘要:然而代码的最终执行结果表明,内的代码运行应该是先于里面的代码。项目中请求服务端异步获取数据的接口参考文档中几种的区别源码阅读启动过程

公司一些管理后台的前端页面,使用的是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", {
    host: domain,
    domain: domain,
    api: this.domain + "/admin", //项目中请求服务端异步获取数据的接口
 }
参考文档:

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/80672.html

相关文章

  • 初探Angular6.x---用户列表与用户详情

    摘要:初探用户列表与用户详情在上一篇博文进入用户编辑中我们分享了属性名称和这两个表达式的运用我们已经可以将表单里的修改与我们展示出来的值进行同步今天我们来学习在中如何展示一个列表在项目里列表展示可以说是非常普遍的一个需求了几乎有展示数   初探Angular6.x---用户列表与用户详情   在上一篇博文《Angular6.x---进入用户编辑》中,我们分享了{{属性名称}}和[(ngMod...

    helloworldcoding 评论0 收藏0
  • 初探Angular6.x---主从组件

    摘要:在上一篇博文用户列表与详情展示中我们用实现了用户列表的展示并通过语法实现了列表单击时将单击的对象传到后台的功能最后为了防止初次加载对象为空导致的错误我们又使用了语法来对要展示的详情对象进行判空操作但随着后续模块的增多以及业务的交叉我们    在上一篇博文《Angular6.x---用户列表与详情展示》中,我们用ngFor=let object of list实现了用户列表的展示,并通过...

    FingerLiu 评论0 收藏0
  • 【nginx学习一】基本原理初探

    摘要:关于过程中如何细节控制一致性,稳定性,信号控制,控制等等,敬请期待小拽的进一步探索处理流程和模块启动进程后,请求在内部是如何流转的,内部包括哪些模块处理过程请求到达后首先读取,中初始时间便从此开始。 由于性能问题,需要将 apache + php5.2 升级到 nginx + php7,对于nginx的性能和热加载早有耳闻,why nginx so diao。小拽进行了初探,有任何疑问...

    Simon 评论0 收藏0
  • React 初探

    摘要:各个组件维护自己的状态和,当状态变更,自动重新渲染整个组件。形式的定义的组件是以的形式来创建的组件的,是目前极为推荐的创建有状态组件的方式,最终会取代形式相对于可以更好实现代码复用。组件名称首字母必须大写。变量名用包裹,且不能加双引号。 目前在前端开发领域,框架Angular、react和vue占据着主流的地位而且可能会持续比较长的一段时间。三门框架中,从数据绑定机制来看,vue和an...

    levy9527 评论0 收藏0
  • React 初探

    摘要:各个组件维护自己的状态和,当状态变更,自动重新渲染整个组件。形式的定义的组件是以的形式来创建的组件的,是目前极为推荐的创建有状态组件的方式,最终会取代形式相对于可以更好实现代码复用。组件名称首字母必须大写。变量名用包裹,且不能加双引号。 目前在前端开发领域,框架Angular、react和vue占据着主流的地位而且可能会持续比较长的一段时间。三门框架中,从数据绑定机制来看,vue和an...

    trilever 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<