国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

試讀angular源碼第一章:開場與platformBrowserDynamic

RiverLi / 1065人閱讀

摘要:而且大部分人一聽說就會本能地避開。至于啟動項目,都是這一行開始的。應用是模塊化的,它擁有自己的模塊化系統,稱作。

開場來個自我介紹

angular 源碼閱讀

項目地址

文章地址

angular 版本:8.0.0-rc.4

歡迎看看我的類angular框架

關于為什么寫這么一個項目

聲明:僅僅為個人閱讀源碼的理解,不一定完全正確,還需要大佬的指點。

其實市面上很多關于 vue和react 的源碼閱讀,但是基本上沒有看到關于 angular 系統性地源碼閱讀。

而且大部分人一聽說 angular 就會本能地避開。

但其實不是的,在我眼里 angular 只是套用了很多后端已有的概念,比如 DI,比如 AOT 等。

之前我寫過一個類 angular 的框架 InDiv,基本上實現了大多數 ng 的裝飾器。

而且在寫這個項目的時候,我從 angular 上學到了很多。

這次,則希望通過閱讀 angular 的源代碼,學習到更多谷歌在設計模式上的運用,學習到更多代碼優化和結構的運用。

也有一點私心,希望更多人說 ng大法好 ,哈哈。

前提

希望看之前讀者能先了解一下 typescripy 和 angular 的基礎概念,因為文章里會出現大量的 DI,服務商啊這類詞

    typescript

    angular文檔

項目結構

項目下只有三個文件夾:angular docs 和 my-demo

- angular: 注釋版angular的ts源代碼
- docs: 文檔位置
- my-demo: 啟動的一個demo項目

通過 tsconfig 把 angular 別名設置到 angular這個文件夾,來閱讀下 ts 版本的源碼。

啟動app

在瀏覽器端,每個 angular app都是從 main.ts 開始的。

import { enableProdMode } from "@angular/core";
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";

import { AppModule } from "./app/app.module";
import { environment } from "./environments/environment";

if (environment.production) {
  enableProdMode();
}

platformBrowserDynamic().bootstrapModule(AppModule)
  .catch(err => console.error(err));

至于啟動項目,都是這一行 platformBrowserDynamic().bootstrapModule(AppModule) 開始的。

在 angular 的世界中,所有的app都是由 bootstrapModule 根模塊或主模塊啟動的。

Angular 應用是模塊化的,它擁有自己的模塊化系統,稱作 NgModule

關于 NgModule

一個 NgModule 就是一個容器,用于存放一些內聚的代碼塊,這些代碼塊專注于某個應用領域、某個工作流或一組緊密相關的功能。

它可以包含一些組件、服務提供商或其它代碼文件,其作用域由包含它們的 NgModule 定義。 它還可以導入一些由其它模塊中導出的功能,并導出一些指定的功能供其它 NgModule 使用。

每個 Angular 應用都至少有一個 NgModule 類,也就是根模塊,它習慣上命名為 AppModule,并位于一個名叫 app.module.ts 的文件中。

引導這個根模塊就可以啟動你的應用

當 bootstrap(引導)根模塊之后,NgModule 會繼而實例化元數據中 bootstrap

bootstrap 應用的主視圖,稱為根組件。它是應用中所有其它視圖的宿主。只有根模塊才應該設置這個 bootstrap 屬性

platform

angular 抽象出 platform,來實現跨平臺。

實例化 angular 根模塊的 bootstrapModule 的方法在瀏覽器端來自 @angular/platform-browser-dynamic

其實除了 @angular/platform-browser-dynamic 之外還有 @angular/platform-browser

這兩個模塊的主要區別是編譯方式的不同, platform-browser-dynamic 提供 JIT 編譯,也就是說編譯在瀏覽器內完成,而 platform-browser 提供 AOT 編譯,編譯在本地完成。

至于區別

platformBrowserDynamic

angular/packages/platform-browser-dynamic/src/platform-browser-dynamic.ts

/**
 * @publicApi
 */
export const platformBrowserDynamic = createPlatformFactory(
    platformCoreDynamic, "browserDynamic", INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS);

platformBrowserDynamic 方法很簡單,就是調用創建平臺的工廠方法 createPlatformFactory 返回的一個返回值是平臺實例 PlatformRef 的函數

createPlatformFactory

angular/packages/core/src/application_ref.ts

/**
 * Creates a factory for a platform
 *
 * @publicApi
 */
export function createPlatformFactory(
    parentPlatformFactory: ((extraProviders");

該方法接受三個參數:

    parentPlatformFactory: ((extraProviders"); 返回父平臺工廠實例的方法

    name: string 平臺的名字

    providers: StaticProvider[] = [] DI的服務提供者

    首先通過 InjectionToken 創建一個 Platform: ${name} 的值提供商

    然后返回一個方法,接受服務提供者 extraProviders");,返回一個平臺實例 PlatformRef

createPlatformFactory 返回的方法

    獲取當前平臺實例

    如果當前平臺實例不存在并且不存在 AllowMultipleToken 這個允許多個令牌的服務提供者

      父級平臺工廠方法 parentPlatformFactory 存在,則合并服務提供商并遞歸調用 parentPlatformFactory

      父級平臺工廠方法 parentPlatformFactory 不存在,則使用注入器創建實例方法 Injector.create 創建實例平臺實例并用 createPlatform 設置為全局的平臺實例

    調用 assertPlatform 確認 IOC 容器中存在 該 marker 的平臺實例并返回

所以創建平臺實例的順序上,應該是 合并 browserDynamic 的 provider => 合并 coreDynamic 的 provider => 合并 provider 并創建 core

大概用人話描述就是:

    判斷是否已經創建過了

    判斷是否有父 Factory

    如果有父 Factory 就把調用 Factory 時傳入的 Provider 和調用 createPlatformFactory 傳入的 Provider 合并,然后調用父 Factory

    如果沒有父 Factory ,先創建一個 Injector ,然后去創建 PlatformRef 實例

createPlatform

angular/packages/core/src/application_ref.ts

let _platform: PlatformRef;

/**
 * Creates a platform.
 * Platforms have to be eagerly created via this function.
 *
 * @publicApi
 */
export function createPlatform(injector: Injector): PlatformRef {
  if (_platform && !_platform.destroyed &&
      !_platform.injector.get(ALLOW_MULTIPLE_PLATFORMS, false)) {
    throw new Error(
        "There can be only one platform. Destroy the previous one to create a new one.");
  }
  _platform = injector.get(PlatformRef);
  const inits = injector.get(PLATFORM_INITIALIZER, null);
  if (inits) inits.forEach((init: any) => init());
  return _platform;
}

_platform 是全局的唯一平臺實例。

創建平臺實例關鍵方法,傳入服務注入器實例 injector 返回平臺實例:

    確認全局的平臺實例存在,狀態不是被銷毀,并且不存在多個平臺實例

    從注入器中獲取平臺實例

    injector.get(PLATFORM_INITIALIZER, null) 獲取初始化平臺時需要執行的函數并執行

回過頭看 platformBrowserDynamic

angular/packages/platform-browser-dynamic/src/platform-browser-dynamic.ts

/**
 * @publicApi
 */
export const platformBrowserDynamic = createPlatformFactory(
    platformCoreDynamic, "browserDynamic", INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS);

重點來了:INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS

這個 providers 究竟提供了什么服務?

angular/packages/platform-browser-dynamic/src/platform_providers.ts

/**
 * @publicApi
 */
export const INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS: StaticProvider[] = [
  INTERNAL_BROWSER_PLATFORM_PROVIDERS,
  {
    provide: COMPILER_OPTIONS,
    useValue: {providers: [{provide: ResourceLoader, useClass: ResourceLoaderImpl, deps: []}]},
    multi: true
  },
  {provide: PLATFORM_ID, useValue: PLATFORM_BROWSER_ID},
];

除了 COMPILER_OPTIONSPLATFORM_ID,大概重點就是 INTERNAL_BROWSER_PLATFORM_PROVIDERS 了吧。

INTERNAL_BROWSER_PLATFORM_PROVIDERS 來自 @angular/platform-browser

angular/packages/platform-browser/src/browser.ts

export const INTERNAL_BROWSER_PLATFORM_PROVIDERS: StaticProvider[] = [
  {provide: PLATFORM_ID, useValue: PLATFORM_BROWSER_ID},
  {provide: PLATFORM_INITIALIZER, useValue: initDomAdapter, multi: true},
  {provide: PlatformLocation, useClass: BrowserPlatformLocation, deps: [DOCUMENT]},
  {provide: DOCUMENT, useFactory: _document, deps: []},
];

@angular/platform-browser 提供了一些瀏覽器端的ng實現:

    PLATFORM_INITIALIZER 是初始化需要執行的方法集合 這個很重要

    DOCUMENT 瀏覽器端的 document_document 工廠方法返回 document

在上面,createPlatform 的時候,會 const inits = injector.get(PLATFORM_INITIALIZER, null); if (inits) inits.forEach((init: any) => init()); 依次執行 PLATFORM_INITIALIZER 注入的工廠方法。

那么來看看 initDomAdapter 吧:

angular/packages/platform-browser/src/browser.ts

export function initDomAdapter() {
  BrowserDomAdapter.makeCurrent();
  BrowserGetTestability.init();
}

    BrowserDomAdapter.makeCurrent(); 通過 BrowserDomAdapter 的靜態方法實例化一個 BrowserDomAdapter 全局DOM適配器 ,具體就是實現并封裝了一些在瀏覽器端的方法,具體的可以看 angular/packages/platform-browser/src/browser/browser_adapter.ts 中的 class BrowserDomAdapter extends GenericBrowserDomAdapter

    BrowserGetTestability.init(); 則是初始化 angular 的測試,這個就沒看了

回過頭看下,在創建 platformBrowserDynamic 時候,傳入了返回父平臺實例的方法 platformCoreDynamic

platformCoreDynamic

angular/packages/platform-browser-dynamic/src/platform_core_dynamic.ts

import {COMPILER_OPTIONS, CompilerFactory, PlatformRef, StaticProvider, createPlatformFactory, platformCore} from "@angular/core";
import {JitCompilerFactory} from "./compiler_factory";

/**
 * A platform that included corePlatform and the compiler.
 *
 * @publicApi
 */
export const platformCoreDynamic = createPlatformFactory(platformCore, "coreDynamic", [
  {provide: COMPILER_OPTIONS, useValue: {}, multi: true},
  {provide: CompilerFactory, useClass: JitCompilerFactory, deps: [COMPILER_OPTIONS]},
]);

platformCoreDynamic 又傳入了

    來自 @angular/core 的 平臺核心 platformCore

    平臺名 coreDynamic

    2個靜態服務提供者:編譯選項 COMPILER_OPTIONSplatformDynamic 的JIT編譯器工廠 JitCompilerFactory

platformCore

angular/packages/core/src/platform_core_providers.ts

import {PlatformRef, createPlatformFactory} from "./application_ref";
import {PLATFORM_ID} from "./application_tokens";
import {Console} from "./console";
import {Injector, StaticProvider} from "./di";
import {TestabilityRegistry} from "./testability/testability";

const _CORE_PLATFORM_PROVIDERS: StaticProvider[] = [
  // Set a default platform name for platforms that don"t set it explicitly.
  {provide: PLATFORM_ID, useValue: "unknown"},
  // 在這里 PlatformRef 被加入了 injector 并在 createPlatformFactory 中實例化
  {provide: PlatformRef, deps: [Injector]},
  {provide: TestabilityRegistry, deps: []},
  {provide: Console, deps: []},
];

/**
 * This platform has to be included in any other platform
 *
 * @publicApi
 */
export const platformCore = createPlatformFactory(null, "core", _CORE_PLATFORM_PROVIDERS);

platformCore 則是創建了一個返回根平臺工廠實例的方法,并設置了4個基礎的DI的服務提供者

    PLATFORM_ID 平臺id

    PlatformRef 在這里 PlatformRef 被加入了 injector 并在后續的 createPlatformFactory 中通過 createPlatform(Injector.create({providers: injectedProviders, name: desc})); 平臺實例會被實例化

    TestabilityRegistry 可測試性注冊表 測試相關

    Console 很有意思 angular 把 Console 作為服務注入了DI,但是 Console 只實現了 log和warn兩個方法

PlatformRef

angular/packages/core/src/application_ref.ts

@Injectable()
export class PlatformRef {
  private _modules: NgModuleRef<any>[] = [];
  private _destroyListeners: Function[] = [];
  private _destroyed: boolean = false;

  /** @internal */
  constructor(private _injector: Injector) {}

  bootstrapModuleFactory(moduleFactory: NgModuleFactory, options");Promise> {
        ...
  }

  bootstrapModule(
      moduleType: Type, compilerOptions: (CompilerOptions&BootstrapOptions)|
      Array = []): Promise> {
    const options = optionsReducer({}, compilerOptions);
    return compileNgModuleFactory(this.injector, options, moduleType)
        .then(moduleFactory => this.bootstrapModuleFactory(moduleFactory, options));
  }

  private _moduleDoBootstrap(moduleRef: InternalNgModuleRef<any>): void {
    ...
  }

  onDestroy(callback: () => void): void { this._destroyListeners.push(callback); }

  get injector(): Injector { return this._injector; }

  destroy() {
    if (this._destroyed) {
      throw new Error("The platform has already been destroyed!");
    }
    this._modules.slice().forEach(module => module.destroy());
    this._destroyListeners.forEach(listener => listener());
    this._destroyed = true;
  }

  get destroyed() { return this._destroyed; }
}

PlatformRef 就是平臺實例的類,有一些方法和屬性等,例如幾個關鍵的方法

    bootstrapModule 引導根模塊的方法

    bootstrapModuleFactory 實例模塊的工廠方法,會運行 zone.js 并監聽事件

    destroy 銷毀平臺實例的方法

這個我們放到后文去說吧

總結

調用 platformBrowserDynamic() 并生成平臺實例 PlatformRef 時大概經歷了這些:

    調用 createPlatformFactory 合并平臺 browserDynamicproviders 并觸發父級平臺 coreDynamic 的平臺工廠函數

    調用 createPlatformFactory 合并平臺 coreDynamicproviders 并觸發父級平臺 core 的平臺工廠函數

    由于平臺 core 無父級平臺,調用 Injector.create 創建 PlatformRef 實例,并賦值給全局唯一的平臺實例 _platform

    createPlatform 創建 PlatformRef 的時候,實例化一個 BrowserDomAdapter 全局DOM適配器 ,具體就是實現并封裝了一些在瀏覽器端的方法

    最后斷言,確認存在 PlatformRef 實例,并返回 PlatformRef 實例

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/7881.html

相關文章

  • angular源碼分析之platformBrowserDynamic

    摘要:生成項目后,中的代碼這里調用了包中導出的函數這個函數是瀏覽器平臺的工廠函數執行會返回瀏覽器平臺的實例函數是通過函數創建的這個函數接收個參數父平臺工廠函數平臺名稱服務提供商的數組顧名思義函數的作用是創建平臺工廠的函數在框架被加 cli生成項目后,main.ts中的代碼 import { enableProdMode } from @angular/core; import { platf...

    FWHeart 評論0 收藏0
  • angular源碼分析之platformBrowserDynamic

    摘要:生成項目后,中的代碼這里調用了包中導出的函數這個函數是瀏覽器平臺的工廠函數執行會返回瀏覽器平臺的實例函數是通過函數創建的這個函數接收個參數父平臺工廠函數平臺名稱服務提供商的數組顧名思義函數的作用是創建平臺工廠的函數在框架被加 cli生成項目后,main.ts中的代碼 import { enableProdMode } from @angular/core; import { platf...

    zhoutao 評論0 收藏0
  • Angular 2.x 從0到1 (一)史上最簡單的Angular2教程

    摘要:官方支持微軟出品,是的超集,是的強類型版本作為首選編程語言,使得開發腳本語言的一些問題可以更早更方便的找到。第一個組件那么我們來為我們的增加一個吧,在命令行窗口輸入。引導過程通過在中引導來啟動應用。它們的核心就是。 第一節:Angular 2.0 從0到1 (一)第二節:Angular 2.0 從0到1 (二)第三節:Angular 2.0 從0到1 (三) 第一章:認識Angular...

    tuniutech 評論0 收藏0
  • 從安裝認識Angular 2

    摘要:首先,要確認安裝了,并且創建了目錄并執行初始化。想必看見上面的那么多包會一臉懵逼,沒關系,我第一眼看見這些的那刻,和你現在的表情一樣,下面在適當的時候我會逐個解釋的,你只需要相信我上面的包都是跑所必須的,缺一不可。 關于介紹,只說一句:Angular 2是一個強大、全面、龐大的MVVM框架。 安裝 安裝,也算是一個坎,因為你需要安裝一大堆東西,卻不知道每個東西是做什么的,盡管有Angu...

    xietao3 評論0 收藏0
  • angular2初入眼簾之-多components協作

    摘要:我們使用了模式書寫,并引入了思想,這些以前只在里見到的設計,現在里也有體現,并且在本章中會著重講解多的協作。如果之前寫過,那對于這種書寫方式一定無比熟悉。每次數據的變更,無論是還是,都將變化冒泡到,然后由再向下逐級推送各組件是否重繪。 前集回顧 在上一章里我們講了如何在angular2下開發一個component(還沒做的趕緊去學吧)。我們使用了Unidirectional Data ...

    dreamans 評論0 收藏0

發表評論

0條評論

RiverLi

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<