<dl id="opymh"></dl>

<div id="opymh"></div>
      <div id="opymh"><tr id="opymh"></tr></div>

        <em id="opymh"><ins id="opymh"><mark id="opymh"></mark></ins></em><sup id="opymh"><menu id="opymh"></menu></sup>

        <em id="opymh"></em>

        <em id="opymh"><ol id="opymh"></ol></em>

              頻道欄目
              首頁 > 程序開發 > web前端 > HTML/CSS > 正文
              我理解的core目錄 Angularx項目開發雜亂隨筆
              2019-03-08 15:19:17           
              收藏   我要投稿

              過了一遍 Angular 文檔 的小伙伴大致都會記得最佳實踐中提到過的有關CoreModule的一些解釋和說明,其實關于名字的命名不是強制性的,只要團隊中一致 pass,你把它命名為XXXModule都無所謂。但是最主要的,還是我們需要理解“core”的作用以及在項目中發揮更好的作用和地位。

              我記錄下我項目中對“core”的一些拙略見解和搭配。

              core目錄

              縱觀整個Angular項目結構以及最佳實踐,我們通常把項目按功能劃分文件夾,比如工具、共享、全局核心、頁面模塊組件、公用模塊組件等等,“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技術培訓 | 舉報中心

              版權所有: 紅黑聯盟--致力于做實用的IT技術學習網站

              极速飞艇好假
              <dl id="opymh"></dl>

              <div id="opymh"></div>
                  <div id="opymh"><tr id="opymh"></tr></div>

                    <em id="opymh"><ins id="opymh"><mark id="opymh"></mark></ins></em><sup id="opymh"><menu id="opymh"></menu></sup>

                    <em id="opymh"></em>

                    <em id="opymh"><ol id="opymh"></ol></em>

                          <dl id="opymh"></dl>

                          <div id="opymh"></div>
                              <div id="opymh"><tr id="opymh"></tr></div>

                                <em id="opymh"><ins id="opymh"><mark id="opymh"></mark></ins></em><sup id="opymh"><menu id="opymh"></menu></sup>

                                <em id="opymh"></em>

                                <em id="opymh"><ol id="opymh"></ol></em>