• 我相信“交警雨中护送高考生”是真,“交警雨中护送高考生”反被该高考生家长投诉是假。 2019-04-16
  • 14名消防员日巡逻28公里 洗冷水澡 2019-04-10
  • 靶壕有了“蓝军”,百发百中的“神枪手”练起来 2019-04-10
  • 不是秀强大了,别人就会来做朋友,这逻辑不对 2019-04-01
  • 候选企业:中国石油呼和浩特石化公司 2019-03-26
  • 航天员沙漠野外生存训练完美收官!为第一天团打call 2019-03-25
  • 请问,建立市场经济后,原计划经济哪里去?改革后,我们还在实行计划经济,为何没有提及? 2019-03-25
  • 构建年轻干部梯次培养链 2019-03-19
  • 孙实的专栏作者中国国家地理网 2019-03-15
  • 湖南师范大学举行研究阐释党的十九大精神国家社科基金重大专项学术研讨会 2019-03-15
  • [雷人]蠢货!土地处于不同的城市和地段,关联的资源不一样,价值也不一样。不然给咱俩同样面积的土地,咱的在北上广深,你的在边远山区,你干么? 2019-03-08
  • 国际社会持续热议上合青岛峰会:上合组织发展进入新阶段 彰显中国领导力 2019-03-08
  • 珍惜野生动物频现甘孜境内 生态环境质量不断提升 2019-03-06
  • "新经济形势下金融创新的变革与机遇"论坛 2019-03-06
  • 频道栏目
    神奇公式秒杀全国11选5 > 程序开发 > web前端 > HTML/CSS > 正文
    我理解的core目录 Angularx项目开发杂乱随笔
    2019-03-08 15:19:17           
    收藏   我要投稿

    过了一遍 Angular 文档 的小伙伴大致都会记得最佳实践中提到过的有关CoreModule的一些解释和说明,其实关于名字的命名不是强制性的,只要团队中一致 pass,你把它命名为XXXModule都无所谓。但是最主要的,还是我们需要理解“core”的作用以及在项目中发挥更好的作用和地位。

    我记录下我项目中对“core”的一些拙略见解和搭配。

    core目录

    神奇公式秒杀全国11选5 www.2zfa.com 纵观整个Angular项目结构以及最佳实践,我们通常把项目按功能划分文件夹,比如工具、共享、全局核心、页面???a href="//www.2zfa.com/kf/all/zujian/" target="_blank" class="keylink">组件、公用??樽榧鹊?,“core”在这里相当于全局核心类型的范围,那全局核心类型到底是聚集了项目的哪些功能呢?我的理解是我们可以把 全局单例服务、只需要引入一次 的东西都归并到这里。

    全局单例服务:这些服务在整个应用生命周期内只存在一个实例,也就是数据是全局互通的,而在 Angular 中实现单例服务就需要一个中间提供商(module)来做中介,也就是所谓的“CoreModule”,然后在根??橐靡淮伪憧扇质褂?,这也是官方推荐的一种单例服务做法。然而在 Angular 6 + 版本后,官方为 Injectable 装饰器提供了 providedIn: 'root' 的选项,让声明的服务直接成为单例服务,此后再不用通过“CoreModule”来提供服务,但是我们的单例服务仍然可以放在 core目录 中,通过 路径别名 配置来直接访问服务,因为实际上,单例服务只会乖乖在 core目录中 ,不会再有其他东西来干扰。 只需引入一次的?:什么是项目中只需要引入一次的?举个例子,全局错误处理、根路由数据预加载、http请求拦截器等。这些都是通过一次配置就能一直用到老的东西,而且不可能会有其他兄弟来直接使用的东西,顺理成章就需要归并到 core目录 中,并且有的需要被“CoreModule”引用,有的需要被“AppModule”引用。

    我列举来几个更加详细的例子来说说这些类别:
    应用初始数据加载

    在开发单页应用特别是管理系统的时候,可能项目的构成除了中心主系统还衍生了很多个子项目系统,这种情况下登录授权一般都是在主系统完成,然后前后端通过单点登录确保子系统能使用。这时子系统一般都是一个新的项目,我们都知道 Angular 提供了强大的路由功能,可以通过路由守卫来预加载系统,然而我们需要的授权信息是相对整个应用而不是某个路由而言的,那这个时候我们就需要一个根级别的数据预加载功能来完成授权等功能。

    Angular 还是帮你开辟好了入口,这时我们只需要一个APP_INITIALIZER就可以完成预加载。前提是我们定义好了预加载的数据操作逻辑,举个例子:

    /**
     * app 初始化前身份验证操作
     */
    @Injectable({
        providedIn: 'root'
    })
    export class AppInitAuthService {
        constructor(
            ...,
            private userInfoService: UserInfoService,
        ) { }
    
        /** 验证当前token身份 */
        tokenAuth(): Promise {
            return new Promise((resolve,reject) => {
                return this.userInfoService.getUserInfoServer().subscribe(res => {
                    if(res.reasonCode == 'notLoggedIn'){
                        //未登录 
                        //可以进行取消授权处理
                        ...
                    }else{
                        //获取了授权数据,todo ...
                        resolve(true)
                    }
                })
            })
         }
    }

    此处声明了一个基本的用户授权信息获取服务,接下来我们可以直接通过APP_INITIALIZER来完成数据预加载功能,只需要在 CoreModule 中声明刚才提供的处理服务,Angular 会自动在根组件初始化前查询并执行 APP_INITIALIZER 所注入的所有服务函数,由于我们提供的是一个 Promise 对象,所以 Angular 会等待执行结果:

    @NgModule({
        ...
        providers: [
            ...
            {
                provide: APP_INITIALIZER,
                multi: true,
                useFactory: (appInit: AppInitAuthService) => {
                    return () => appInit.tokenAuth()
                },
                deps: [AppInitAuthService]
            }
        ]
    })
    export class CoreModule {
        constructor(
            ...
        ) {}
    }

    只要AppModule引用了CoreModule,项目会自动完成预授权处理功能,完全无需其他组件掺入。全局错误处理

    有时候我们需要全局错误处理机制。比如我们编译更新了项目版本,多个某个??楣δ?,但是用户这边并没有去实时刷新,当意外去到某个原本不存在的路由时 Angular 会捕获到找不到??榈拇砦?,这是我们就可以提前在错误处理中去对用户进行较友好的提示等等;又比如我们会想要去接入前端监控平台像 fundebug 等等,具体对实现方式也是一样通过 Angular 提供的捕错功能来实现。

    一个最简单的错误处理服务如下:

    import { ErrorHandler } from '@angular/core'
    
    export class HandleCommon extends ErrorHandler{
        constructor(){
            super()
        }
    
        handleError(error: Error){
            //注意调基类处理函数,不然会覆盖默认行为,比如控制台不会看到报错
            super.handleError(error)
            if (/Loading chunk [\d]+ failed/.test(error.message)) {
                //捕获找不到???(服务端目录数据变动)
                ...
            } 
            //... 各种错误处理    
        }
    }

    然后我们直接在AppModule中声明一个 ErrorHandler 令牌对应的服务,就可以实现全局错误监听处理:

    import { NgModule, ErrorHandler } from '@angular/core'
    import { HandleCommon } from '../core'
    
    @NgModule({
        ...
        providers: [
            ...
            {
                provide: ErrorHandler,
                useFactory: () => {
                    return new HandleCommon()
                }
            }
        ],
        bootstrap: [
            AppComponent
        ]
    })
    export class AppModule { }
    
    http请求拦截器

    尽管 Angular 提供了十分漂亮的 HttpClient 给开发者舒服地进行网络请求操作,但是有很多针对网络请求的需求需要我们自己去开发,像 http 超时拦截、token 拦截、错误处理拦截等等,这些也都属于一次引用,全局使用的范畴。更漂亮的是 Angular 为我们提供了拦截器接口,我们只管开发拦截器逻辑功能,调用及使用全部控制权都在框架内。由于拦截器涉及比较多东西,这里放一个最为简单的实现如下:

    import {
        HttpInterceptor,
        HttpRequest,
        HttpHandler,
        HttpEvent
    } from '@angular/common/http'
    import { Injectable } from '@angular/core'
    import { Observable } from 'rxjs'
    import { tap } from 'rxjs/operators'
    
    //拦截器 - 添加请求头
    @Injectable()
    export class TokenInterceptor implements HttpInterceptor {
    
        constructor() { }
    
        intercept(req: HttpRequest, next: HttpHandler): Observable> {
            //通过某些逻辑获取 token
            let token = 'xxxx'
            if (token) {
                token = `Bearer ${token}`
                req = req.clone({
                    setHeaders: {
                        Authorization: token
                    }
                })
            }
            return next.handle(req)
        }
    }

    只需要在 CoreModule 中通过 HTTP_INTERCEPTORS 令牌来声明我们写好的拦截器,框架会在正确的时机自动处理和调用拦截器逻辑:

    @NgModule({
        providers: [
            ...,
            {
                provide: HTTP_INTERCEPTORS,
                useClass: TokenInterceptor,
                //必须设置,拦截器是个数组集合而不仅仅只有一个
                multi: true
            }
        ]
    })
    export class CoreModule {
        constructor() {}
    }
    
    一些单例服务等等

    应用中或多或少有一些需要在全局流通的数据,比如全局的用户信息管理:

    @Injectable({
        providedIn: 'root'
    })
    export class UserInfoService {
        //用户数据 全局共享 数据流
        userInfo$: BehaviorSubject = new BehaviorSubject(null)
    
        constructor() { }
    
        /**
         * 获取用户数据
         */
        getUserInfoServer(): Observable {
            ...
        }
    
        /**
         * 退出登录
         */
        getUserLogoutServer(): Observable {
            ...
        }
    }

    作为频繁被存取的介质,单例模式自然而然是它的特点,所以最好也一起归并到所谓的 core目录 中。

    因人而异

    前面列举了一些常用的类别来说明 core目录 以及 “CoreModule” 存在的意义。除了一些需要“CoreModule”来作为桥梁的例子,貌似 core目录 并不是必须要存放某些东西的,比如全局的单例对象就完全可以单独使用其他的文件夹来存放维护。是对的,没有一个统一的标准来约束我们到底是要去如何组织代码目录结构,所有项目都是因人而异,自己觉得舒服的、可维护的才最重要。

    本记录只是为了更加贴近官方最佳实践而如此组织,纯粹作为一个记录以及给大家的一个参考。

    点击复制链接 与好友分享!回本站首页
    相关TAG标签 开发
    上一篇:react中使用css的7中方式(应该是最全的)
    下一篇:2019面试笔记个人文章
    相关文章
    图文推荐
    点击排行

    关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 神奇公式秒杀全国11选5

    版权所有: 神奇公式秒杀全国11选5--致力于做实用的IT技术学习网站

  • 我相信“交警雨中护送高考生”是真,“交警雨中护送高考生”反被该高考生家长投诉是假。 2019-04-16
  • 14名消防员日巡逻28公里 洗冷水澡 2019-04-10
  • 靶壕有了“蓝军”,百发百中的“神枪手”练起来 2019-04-10
  • 不是秀强大了,别人就会来做朋友,这逻辑不对 2019-04-01
  • 候选企业:中国石油呼和浩特石化公司 2019-03-26
  • 航天员沙漠野外生存训练完美收官!为第一天团打call 2019-03-25
  • 请问,建立市场经济后,原计划经济哪里去?改革后,我们还在实行计划经济,为何没有提及? 2019-03-25
  • 构建年轻干部梯次培养链 2019-03-19
  • 孙实的专栏作者中国国家地理网 2019-03-15
  • 湖南师范大学举行研究阐释党的十九大精神国家社科基金重大专项学术研讨会 2019-03-15
  • [雷人]蠢货!土地处于不同的城市和地段,关联的资源不一样,价值也不一样。不然给咱俩同样面积的土地,咱的在北上广深,你的在边远山区,你干么? 2019-03-08
  • 国际社会持续热议上合青岛峰会:上合组织发展进入新阶段 彰显中国领导力 2019-03-08
  • 珍惜野生动物频现甘孜境内 生态环境质量不断提升 2019-03-06
  • "新经济形势下金融创新的变革与机遇"论坛 2019-03-06