Angular 源码翻译之core package

core package

概要:
Core是所有其他包的基础包.它提供了大部分功能包括metadata,template linker,Ng module系统,application初始化,di,i18n,animation,WTF( Web Tracing Framework),和NgZone,Sanitizer,SecurityContext.这样的基础类型。
核心API:
core根目录中的index.ts对外暴露了public-api文件中的内容,而public-api中的内容对外暴露src/core.ts中的内容:
<meta charset="utf-8">

● <ANGULAR-MASTER>/p ackages/core/src/core.ts

以下是core对外提供的API定义:

export * from './metadata';

export * from './version';

export {TypeDecorator} from './util/decorators';

export * from './di';

export {createPlatform, assertPlatform, destroyPlatform, getPlatform,

PlatformRef, ApplicationRef, enableProdMode, isDevMode,

createPlatformFactory, NgProbeToken} from './application_ref';

export {APP_ID, PACKAGE_ROOT_URL, PLATFORM_INITIALIZER, PLATFORM_ID,

APP_BOOTSTRAP_LISTENER} from './application_tokens';

export {APP_INITIALIZER, ApplicationInitStatus} from './application_init';

export * from './zone';

export * from './render';

export * from './linker';

export {DebugElement, DebugNode, asNativeElements,

getDebugNode, Predicate} from './debug/debug_node';

export {GetTestability, Testability, TestabilityRegistry,

setTestabilityGetter} from './testability/testability';

export * from './change_detection';

export * from './platform_core_providers';

export {TRANSLATIONS, TRANSLATIONS_FORMAT, LOCALE_ID,

MissingTranslationStrategy} from './i18n/tokens';

export {ApplicationModule} from './application_module';

export {wtfCreateScope, wtfLeave, wtfStartTimeRange,

wtfEndTimeRange, WtfScopeFn} from './profile/profile';

export {Type} from './type';

export {EventEmitter} from './event_emitter';

export {ErrorHandler} from './error_handler';

export * from './core_private_export';

export {Sanitizer, SecurityContext} from './security';

export * from './codegen_private_exports';

export * from './animation/animation_metadata_wrapped';

import {AnimationTriggerMetadata}

from './animation/animation_metadata_wrapped';

如果你正在编写一个angular应用,则需要引入core包中index.ts文件。该文件中有两个额外导出的文件,它们仅在angular内部使用并允许其他angular包从core包(这里的包指不在index.ts中的内容)中引入额外的types。在core的src目录下有两个名为private_exports(whereas index.ts在core的根目录)

第一个private_export.ts:

● <ANGULAR-MASTER>/packages/ core/src/core_private_export.ts

其中有以下导出内容:

export {ALLOW_MULTIPLE_PLATFORMS as ɵALLOW_MULTIPLE_PLATFORMS} from

'./application_ref';

export {APP_ID_RANDOM_PROVIDER as ɵAPP_ID_RANDOM_PROVIDER} from

'./application_tokens';

export {ValueUnwrapper as ɵValueUnwrapper, devModeEqual as ɵdevModeEqual}

from './change_detection/change_detection_util';

export {isListLikeIterable as ɵisListLikeIterable} from

'./change_detection/change_detection_util';

export {ChangeDetectorStatus as ɵChangeDetectorStatus,

isDefaultChangeDetectionStrategy as ɵisDefaultChangeDetectionStrategy} from

'./change_detection/constants';

export {Console as ɵConsole} from './console';

export {ComponentFactory as ɵComponentFactory} from

'./linker/component_factory';

export {CodegenComponentFactoryResolver as ɵCodegenComponentFactoryResolver}

from './linker/component_factory_resolver';

export {ReflectionCapabilities as ɵReflectionCapabilities} from

'./reflection/reflection_capabilities';

export {GetterFn as ɵGetterFn, MethodFn as ɵMethodFn, SetterFn as ɵSetterFn}

from './reflection/types';

export {DirectRenderer as ɵDirectRenderer, RenderDebugInfo as

ɵRenderDebugInfo} from './render/api';

export {global as ɵglobal, looseIdentical as ɵlooseIdentical, stringify as

ɵstringify} from './util';

export {makeDecorator as ɵmakeDecorator} from './util/decorators';

export {isObservable as ɵisObservable, isPromise as ɵisPromise} from

'./util/lang';

export {clearOverrides as ɵclearOverrides, overrideComponentView as

ɵoverrideComponentView, overrideProvider as ɵoverrideProvider} from

'./view/index';

export {NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR as

ɵNOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR} from './view/provider';

We observe that the exports are being renamed with the Greek Theta symbol (looks

like a ‘o’ with a horizontal line through it) – all are exported as:

export X as ɵX;

For an explanation see here -

https://stackoverflow.com/questions/45466017/%C9%B5-theta-like-symbol-inangular-

2-source-code

“The letter ɵ is used by the Angular team to indicate that some method is

private to the framework and must not be called directly by the user, as the

API for these method is not guaranteed to stay stable between Angular

versions (in fact, I would say it’s almost guaranteed to break).”

以上概要为不可直接将内部接口名暴露对外

第二个private_export.ts:
● <ANGULAR-MASTER>/packages/ core/src /codegen_private_exports.ts
其中有如下导出内容 :
export {CodegenComponentFactoryResolver as ɵCodegenComponentFactoryResolver}
from './linker/component_factory_resolver';
export {registerModuleFactory as ɵregisterModuleFactory} from
'./linker/ng_module_factory_loader';
export {ArgumentType as ɵArgumentType, BindingFlags as ɵBindingFlags,
DepFlags as ɵDepFlags, EMPTY_ARRAY as ɵEMPTY_ARRAY, EMPTY_MAP as ɵEMPTY_MAP,
NodeFlags as ɵNodeFlags, QueryBindingType as ɵQueryBindingType,
QueryValueType as ɵQueryValueType, ViewDefinition as ɵViewDefinition,
ViewFlags as ɵViewFlags, anchorDef as ɵand, createComponentFactory as ɵccf,
createNgModuleFactory as ɵcmf, createRendererType2 as ɵcrt, directiveDef as
ɵdid, elementDef as ɵeld, elementEventFullName as ɵelementEventFullName,
getComponentViewDefinitionFactory as ɵgetComponentViewDefinitionFactory,
inlineInterpolate as ɵinlineInterpolate, interpolate as ɵinterpolate,
moduleDef as ɵmod, moduleProvideDef as ɵmpd, ngContentDef as ɵncd, nodeValue
as ɵnov, pipeDef as ɵpid, providerDef as ɵprd, pureArrayDef as ɵpad,
pureObjectDef as ɵpod, purePipeDef as ɵppd, queryDef as ɵqud,
textDef as ɵted, unwrapValue as ɵunv, viewDef as ɵvid} from './view/index';

Source Tree Layout
The Core source tree is at:
● <ANGULAR-MASTER>/packages/core
The source tree for the Core package contains these directories:
● src
● test (unit tests in Jasmine)
● testing (test tooling)
and these files:
● BUILD.bazel
● index.ts
● package.json
● public_api.ts
● rollup.config.js
● tsconfig-build.json

Source
core/src
core/src目录中包含很多文件,这些可以分为三类
首先,许多文件只是从等价的命名子目录中导出类型。
● change_detection.ts
● core.ts
● di.ts
● metadata.ts
● linker.ts
● render.ts
● zone.ts
For example, the renderer.ts file is a one-liner that just exports from renderer/api.ts:
export {RenderComponentType, Renderer, Renderer2, RendererFactory2,
RendererStyleFlags2, RendererType2, RootRenderer} from './render/api';
and zone.ts file is a one-liner that just exports from zone/ng_zone.ts:
export {NgZone} from './zone/ng_zone';

  1. 一些包含通用功能的文件
    ● console.ts
    ● error_handler.ts
    ● platform_core_providers.ts
    ● security.ts
    ● types.ts
    ● util.ts
    ● version.ts

  2. 与platform与应用初始化相关的文件
    ● application_init.ts
    ● application_module.ts
    ● application_tokens.ts
    ● application_ref.ts
    前三个文件很小,只有50-70行代码,然而application_ref却超过了500行。
    让我们从aplication_tokens.ts开始,它包含一个provider definition和一系列不同用途的不透明token。PLATFORM_INITIALIZER是一不透明令牌,angular自身与application code可以使用它来注册平台初始化过程中执行的函数。
    // A function that will be executed when a platform is initialized.
    export const PLATFORM_INITIALIZER =

      new InjectionToken<Array<() => void>>('Platform Initializer');
    

下面是一个在platform-browser中使用PLATFORM_INITIALIZER的例子
● <ANGULAR-MASTER>/packages/platform-browser/src/browser.ts
这里被用来在初始化platform时调用initDomAdapter函数(注意multi的使用-这里意思是指多个这样的初始化函数都可以被注册)
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,

{provide: DOCUMENT, useFactory: _document, deps: []},

];
INTERNAL_BROWSER_PLATFORM_PROVIDERS在browser.ts后用了很少的代码创建了浏览器platform(这种方式是大多数angular应用使用的)
另一个在application_tokens.ts中的不透明令牌是PACKAGE_ROOT_URL-用来发现应用的跟目录。
这些通过APP_ID标示的provider 提供了一个可以生成应用表示的唯一字符串。
export const APP_ID = new InjectionToken<string>('AppId');
有一种默认实现是使用Math.random,它被用来创建一个APP_ID_RANDOM_PROVIDER:
function _randomChar(): string {

return String.fromCharCode(97 + Math.floor(Math.random() * 25));

}

export function _appIdRandomProviderFactory() {

return `${_randomChar()}${_randomChar()}${_randomChar()}`;

}

export const APP_ID_RANDOM_PROVIDER = {
provide: APP_ID,
useFactory: _appIdRandomProviderFactory,
deps: <any[]>[],

};

application_init.ts定义了一个不透明的令牌和一个可注入的服务.这个令牌是:
// A function that will be executed when an application is initialized.
export const APP_INITIALIZER =

         new InjectionToken<Array<() => void>>('Application Initializer');

APP_INITIALIZER的角色与PLATFORM_INITIALIZER相同,只不过APP_INITIALIZER是在应用初始化时调用的。这个可注入的服务是ApplicationInitStatus,它可以返回正在执行中的初始化程序的状态。
// 一个可以反应运行状态的类
@Injectable()
export class ApplicationInitStatus {

private resolve: Function;
private reject: Function;
private initialized = false;
public readonly donePromise: Promise<any>;
public readonly done = false;

constructor(@Inject(APP_INITIALIZER)

@Optional() private appInits: (() => any)[]) {

  this.donePromise = new Promise((res, rej) => {
    this.resolve = res;
this.reject = rej;
  });

}
我们将很快看到它在application_ref.ts中是如何被使用的。

application_module.ts定义了ApplicationModule类:
/**

  • 这个模块包括@angular/core中通过ApplicationRef来启动组件的providers
    */

@NgModule({
providers: [

  ApplicationRef,
  ApplicationInitStatus,
  Compiler,
  APP_ID_RANDOM_PROVIDER,
  {provide: IterableDiffers, useFactory: _iterableDiffersFactory},
  {provide: KeyValueDiffers, useFactory: _keyValueDiffersFactory},
  {

    provide: LOCALE_ID,
    useFactory: _localeFactory,
    deps: [[new Inject(LOCALE_ID), new Optional(), new SkipSelf()]]

}, ]
})
export class ApplicationModule {

// Inject ApplicationRef to make it eager...

constructor(appRef: ApplicationRef) {}

}
Providers被用来提供给Angular的依赖注入系统.IterableDiffers and KeyValueDiffers提供了与变更检测相关的服务。ViewUtils被定义在src/linker的子目录中,它包含和渲染相关的公用样式代码。应用开发人员想要知道angular是如何真正工作的,那么就非常需要认真学习application_ref.ts中的代码。让我们从createPlatformFactory()这个函数开始我们的学习

在application_ref.ts中的类型在如何让整个angular基础设施工作上扮演着重要的角色.
此处是createPlatformFactory的实现++++

这个方法接受三个参数:parentPlatformFactory, 2 name and an 3 array of
providers,返回一个工厂函数,当它被调用时会返回一个PlatformRef。

这个工厂函数首先创建一个不透明令牌用来根据提供的名字获取注入实例;然后调用getPlatform()查看是否存在platform(在任何时候都只允许存在一个platform),如果返回false则会调用createPlatform(),同时把调用结果传给ReflectiveInjector’s resolveAndCreate(xx参数)。然后传入marker调用assertPlatform,其返回结果为工厂函数。

PlatformRef定义如下:
@Injectable()
export class PlatformRef {

private _modules: NgModuleRef<any>[] = [];
private _destroyListeners: Function[] = [];
private _destroyed: boolean = false;

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

bootstrapModuleFactory<M>(
   moduleFactory: NgModuleFactory<M>,
   options?: BootstrapOptions): Promise<NgModuleRef<M>> {   }

bootstrapModule<M>(
     moduleType: Type<M>,

compilerOptions: (CompilerOptions&BootstrapOptions)|Array<CompilerOptions&BootstrapOptions>=[] ) : Promise<NgModuleRef<M>> { }
private _moduleDoBootstrap(moduleRef: InternalNgModuleRef<any>): void { }
onDestroy(callback: () => void): void { }
get injector(): Injector { return this._injector; }
destroy() { }

get destroyed() { return this._destroyed; }

}

一个platform呈现着运行一个或多个执行应用的宿主环境.angular中提供了不同的平台(例如浏览器ui,web worker,server与自定义).对于一个web页面,platform代表了应用代码如何与页面相互交流。PlatformRef代表platform,它提供了两个主要功能-根注入与模块启动。其他的member用来处理不再使用的销毁中的资源。

PlatformRef的具体实现管理着传入构造函数中的root injector,NgModuleRefs数组and an array of destroy listeners. 在构造函数中接收注入内容. 注意调用platform的destory()方法将会导致使用该平台的所有应用的destory方法都被调用。

两个启动方法:bootstrapModule and bootstrapModuleFactory.
对任何一个angular团队的重要决定时何时使用runtime compilation,何时使用offline compilation. runtime compilation更容易使用并且作为官网的快速开始示例.runtime compilation使应用更大(模板编译器需要运行在浏览器中导致变大)并且更慢(模板编译在模板使用前运行).使用runtime compilation的应用需要调用bootstrapModule.offline compilation需要额外的时间来编译配置所以配置难度稍为有些复杂,但是由于它的优势导致它更适合大型生产应用.使用offline compilation需要调用bootstrapModuleFactory().

// bootstrapModule实现+++
bootstrapModule首先调用模板编译器然后调用bootstrapModuleFactory,因此在编译器调用完成后,两种启动方式今后的运行是相同的。

当学习zones时我们已经看到了zones在bootstrapModuleFactory的使用,其他重要的代码包括moduleRef与调用_moduleDoBootstrap(moduleRef)的部分:
<meta charset="utf-8">

clipboard.png

在_moduleDoBootstrap中可以看到真正启动的流程:
private _moduleDoBootstrap(moduleRef: InternalNgModuleRef < any > ): void {
const appRef = moduleRef.injector.get(ApplicationRef) as ApplicationRef;
if (moduleRef._bootstrapComponents.length > 0) {
moduleRef._bootstrapComponents.forEach(f => appRef.bootstrap(f));
} else if (moduleRef.instance.ngDoBootstrap) {
moduleRef.instance.ngDoBootstrap(appRef);
} else {
throw new Error(
The module ${stringify(moduleRef.instance.constructor)} was bootstrapped, but it does not declare "@NgModule.bootstrap" components nor a "ngDoBootstrap" method. +
Please define one of these.);
}
this._modules.push(moduleRef);
}

2.png

除了启动功能外,在core/src/application_ref.ts也有一些platform-related functions。createPlatform()创建平台实例,更准确的说该函数通过injector获取平台应用然后调用初始化程序。
/**

  • Creates a platform.
  • Platforms have to be eagerly created via this function.
    */
    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实例._platform定义如下
    let _platform: PlatformRef;
    getPlatform()定义如下:
    export function getPlatform(): PlatformRef|null {
    return _platform && !_platform.destroyed ? _platform : null;
    }
    assertPlatform()函数主要确认两件是事:
  1. 确认platform存在
  2. platform的injector有一个存在令牌的被制定作为参数的provider
    /**
  • Checks that there currently is a platform which contains the
  • given token as a provider.
    */
    export function assertPlatform(requiredToken: any): PlatformRef {
    const platform = getPlatform();
    if (!platform) { throw new Error('No platform exists!'); }
    if (!platform.injector.get(requiredToken, null)) {
    throw new Error(
    'A platform with a different configuration has been created.
    Please destroy it first.
    ');
    }
    return platform;
    }
    destroyPlatform()函数调用了平台销毁方法:
    export function destroyPlatform(): void {
    if (_platform && !_platform.destroyed) {
    _platform.destroy();
    }
    }
    run mode表示平台为开发模式还是生产模式,默认为开发模式:
    let _devMode: boolean = true;
    let _runModeLocked: boolean = false;
    This can be set by calling enableProdMode():
    export function enableProdMode(): void {
    if (_runModeLocked) {
    throw new Error('Cannot enable prod mode after platform setup.');
    }
    _devMode = false;
    }
    决定何种模式需要调用isDevMode().这个方法返回的总是同一个值.换句话说,无论哪个模式被激活,当该函数第一次被调用时获取的mode会一直处于激活状态。
    export function isDevMode(): boolean {
    _runModeLocked = true;
    return _devMode;
    }

ApplicationRef定义如下:
@Injectable()
export class ApplicationRef {
public readonly componentTypes: Type < any > [] = [];
public readonly components: ComponentRef < any > [] = [];
public readonly isStable: Observable < boolean > ;
bootstrap < C > (componentOrFactory: ComponentFactory < C > | Type < C > ,
rootSelectorOrNode ? : string | any): {}
tick(): void {}
attachView(viewRef: ViewRef): void {}
detachView(viewRef: ViewRef): void {}
get viewCount() { return this._views.length; }
}
它的主要方法是bootstrap(),这个方法会生成一个带有type parameter的方法,该方法负责将组建绑定到DOM元素并建立可执行应用。需要注意bootstrap的参数是一个集合类型,它可以作为ComponentFactory或一个Type来呈现,这两种类型都带有C。.(both of which take C as a type parameter)

有一个ApplicationRef的具体实现已经提供了,命名为ApplicationRef_.该实例被标记为Injectable()并维护以下状态:
static _tickScope: WtfScopeFn = wtfCreateScope('ApplicationRef#tick()');
private _bootstrapListeners: ((compRef: ComponentRef<any>) => void)[] = [];
private _views: InternalViewRef[] = [];
private _runningTick: boolean = false;
private _enforceNoNewChanges: boolean = false;
private _stable = true;
它个构造函数显示了注入内容并创建可观测的对象(这里的代码是简写版):
constructor(
private _zone: NgZone,
private _console: Console,
private _injector: Injector,
private _exceptionHandler: ErrorHandler,
private _componentFactoryResolver: ComponentFactoryResolver,
private _initStatus: ApplicationInitStatus) {
this._enforceNoNewChanges = isDevMode();
this._zone.onMicrotaskEmpty.subscribe({ next: () => { this._zone.run(() => { this.tick(); }); } });
const isCurrentlyStable = new Observable < boolean > ((observer: Observer < boolean > ) => {});
const isStable = new Observable < boolean > ((observer: Observer < boolean > ) => {
// Create the subscription to onStable outside the Angular Zone so that
// the callback is run outside the Angular Zone.
let stableSub: Subscription;
this._zone.runOutsideAngular(()
});
const unstableSub: Subscription = this._zone.onUnstable.subscribe();
});
return () => {
stableSub.unsubscribe();
unstableSub.unsubscribe();
};
});
(this as { isStable: Observable < boolean > }).isStable =
merge(isCurrentlyStable, share.call(isStable));

bootstrap()的具体实现传入run function,传入的componentFactory在内部会通过create()来创建component然后_loadComponent().
bootstrap < C > (componentOrFactory: ComponentFactory < C > | Type < C > ,
rootSelectorOrNode ? : string | any):
ComponentRef < C > {
let componentFactory: ComponentFactory < C > ;
if (componentOrFactory instanceof ComponentFactory) {
componentFactory = componentOrFactory;
} else {
componentFactory = this._componentFactoryResolver
.resolveComponentFactory(componentOrFactory) !;
}
this.componentTypes.push(componentFactory.componentType);
// Create a factory associated with the current module if
// it's not bound to some other
const ngModule = componentFactory instanceof
ComponentFactoryBoundToModule ? Null : this._injector.get(NgModuleRef);
const selectorOrNode = rootSelectorOrNode || componentFactory.selector;
const compRef = componentFactory.create(Injector.NULL, [],
selectorOrNode, ngModule);
..
this._loadComponent(compRef);
..
return compRef;
}

_loadComponent定义如下:
private _loadComponent(componentRef: ComponentRef < any > ): void {
this.attachView(componentRef.hostView);
this.tick();
this.components.push(componentRef);
// Get the listeners lazily to prevent DI cycles.
const listeners = this._injector.get(APP_BOOTSTRAP_LISTENER, [])
.concat(this._bootstrapListeners);
listeners.forEach((listener) => listener(componentRef));
}
能绑定到一个view container并接受变更检测的视图成为已绑定的视图.这种视图会被绑定与检测变化,并且这些被绑定的视图会被记录。
private _views: InternalViewRef[] = [];
attachView(viewRef: ViewRef): void {
const view = (viewRef as InternalViewRef);
this._views.push(view);
view.attachToAppRef(this);
}
detachView(viewRef: ViewRef): void {
const view = (viewRef as InternalViewRef);
remove(this._views, view);
view.detachFromAppRef();
}
get viewCount() { return this._views.length; }
core/src/util
The core/src/util directory contains two files:
● decorators.ts
● lang.ts
decorators.ts includes definition of the TypeDecorator class, which is the basis for
Angular’s type decorators. Its makeDecorator() function uses reflection to examine
annotations and returns a decoratorFactory function declared inline. Similar make
functions are supplied for parameters and properties.

Core/DependencyInjection Feature (core/src/di)
core/src/di.ts源文件中会到处很多种的类
export * from './di/metadata';
export { forwardRef, resolveForwardRef, ForwardRefFn } from './di/forward_ref';
export { Injector } from './di/injector';
export { ReflectiveInjector } from './di/reflective_injector';
export {
StaticProvider,
ValueProvider,
ExistingProvider,
FactoryProvider,
Provider,
TypeProvider,
ClassProvider
}
from './di/provider';
export { ResolvedReflectiveFactory, ResolvedReflectiveProvider }
from './di/reflective_provider';
export { ReflectiveKey } from './di/reflective_key';
export { InjectionToken } from './di/injection_token';
core/src/di目录包含以下这些文件:
● forward_ref.ts
● injection_token.ts
● injector.ts
● metadata.ts
● opaque_token.ts
● provider.ts
● reflective_errors.ts
● reflective_injector.ts
● reflective_key.ts
● reflective_provider.ts

metadata.ts中定义了一下接口:
export interface InjectDecorator {
(token: any): any;
new(token: any): Inject;
}
export interface Inject { token: any; }
export interface OptionalDecorator {
(): any;
new(): Optional;
}
export interface Optional {}
export interface InjectableDecorator {
(): any;
new(): Injectable;
}
export interface Injectable {}
export interface SelfDecorator {
(): any;
new(): Self;
}
export interface Self {}
export interface SkipSelfDecorator {
(): any;
new(): SkipSelf;
}
export interface SkipSelf {}
export interface HostDecorator {
(): any;
new(): Host;
}
export interface Host {}
metadata.ts也定义了一下这些变量:
export const Self: SelfDecorator = makeParamDecorator('Self');
export const SkipSelf: SkipSelfDecorator = makeParamDecorator('SkipSelf');
export const Inject: InjectDecorator = makeParamDecorator('Inject', (token:
any) => ({token}));
export const Optional: OptionalDecorator = makeParamDecorator('Optional');
export const Injectable: InjectableDecorator = makeDecorator('Injectable');
export const Host: HostDecorator = makeParamDecorator('Host');
Forward refs are placeholders used to faciliate out-of-sequence type declarations.
forward_ref.ts文件定义了一个接口和两个函数:
export interface ForwardRefFn {
(): any; }
export function forwardRef(forwardRefFn: ForwardRefFn): Type < any > {
( < any > forwardRefFn).forward_ref = forwardRef;
( < any > forwardRefFn).toString = function() { return stringify(this()); };
return ( < Type < any >> < any > forwardRefFn);
}
export function resolveForwardRef(type: any): any {
if (typeof type === 'function' && type.hasOwnProperty('forward_ref') &&
type.forward_ref === forwardRef) {
return ( < ForwardRefFn > type)();
} else {
return type;
}
}
injector.ts文件定义了Injector抽象类:
export abstract class Injector {
static THROW_IF_NOT_FOUND = _THROW_IF_NOT_FOUND;
static NULL: Injector = new _NullInjector();
abstract get < T > (token: Type < T > | InjectionToken < T > , notFoundValue ? : T): T;
abstract get(token: any, notFoundValue ? : any): any;
static create(providers: StaticProvider[], parent ? : Injector): Injector {
return new StaticInjector(providers, parent);
}
}
应用程序的代码(事实上应该是Angular内部代码)给Injector.get()传递一个token,然后函数的具体实现会返回一个匹配token的实例.这个抽象类的具体实现需要重写get()方法,它会根据具体实现来运行。reflective_injector.ts是该抽象类的一个派生类。

provider.ts定义了很多Provider类然后使用它们确定具体的provider类型:
export type Provider =
TypeProvider | ValueProvider | ClassProvider |
ExistingProvider | FactoryProvider| any[];

Core/Metadata Feature (core/src/metadata):元数据功能
元数据可以理解为用来连接其他内容的小块信息.<ANGULAR-MASTER>/core/src/ meta data.ts文件导出了 很多类型
export {
ANALYZE_FOR_ENTRY_COMPONENTS,
Attribute,
ContentChild,
ContentChildDecorator,
ContentChildren,
ContentChildrenDecorator,
Query,
ViewChild,
ViewChildDecorator,
ViewChildren,
ViewChildrenDecorator
}
from './metadata/di';
export {
Component,
ComponentDecorator,
Directive,
DirectiveDecorator,
HostBinding,
HostListener,
Input,
Output,
Pipe
}
from './metadata/directives';
export {
AfterContentChecked,
AfterContentInit,
AfterViewChecked,
AfterViewInit,
DoCheck,
OnChanges,
OnDestroy,
OnInit
}
from './metadata/lifecycle_hooks';
export {
CUSTOM_ELEMENTS_SCHEMA,
ModuleWithProviders,
NO_ERRORS_SCHEMA,
NgModule,
SchemaMetadata
}
from './metadata/ng_module';
export { ViewEncapsulation } from './metadata/view';

The source files in the <ANGULAR-MASTER>/packages/ core/src/metadata subdirectory
are:
● di.ts
● directives.ts
● lifecycle_hooks.ts
● ng_module.ts
● view.ts
di.ts为装饰器定义了一系列接口-这些接口包括AttributeDecorator, ContentChildrenDecorator, ContentChildDecorator,ViewChildrenDecorator, ViewChildDecorator.它还定义和导出了一些使用makePropDecorator创建的接口的实现。

view.ts文件定了一一个枚举类型,一个var变量和一个类。ViewEncapsulation定义如下:
export enum ViewEncapsulation {
Emulated = 0,
Native = 1,
None = 2
}
这些枚举内容表现出模板与样式以何种模式封装.None表示不使用任何封装,Native表示使用shadow DOM来实现封装,Emulated的封装模式在注释中有所解释:
/**

  • Emulate Native scoping of styles by adding an attribute containing
  • surrogate id to the Host Element and pre-processing the style rules
  • provided via {@link Component#styles styles} or
  • {@link Component#styleUrls styleUrls}, and adding the new
  • Host Element attribute to all selectors.
  • This is the default option.
    */
    directives.ts文件对外暴露了指令元数据相关的接口,它们包括:
    ● DirectiveDecorator
    ● Directive
    ● ComponentDecorator
    ● Component
    ● PipeDecorator
    ● Pipe
    ● InputDecorator
    ● Input
    ● OutputDecorator
    ● Output
    ● HostBindingDecorator
    ● HostBinding
    ● HostListenerDecorator
    ● HostListener

lifecycle_hooks.ts中定义了许多鱼生命周期钩子相关的接口:
export interface SimpleChanges { [propName: string]: SimpleChange; }
export interface OnChanges { ngOnChanges(changes: SimpleChanges): void; }
export interface OnInit { ngOnInit(): void; }
export interface DoCheck { ngDoCheck(): void; }
export interface OnDestroy { ngOnDestroy(): void; }
export interface AfterContentInit { ngAfterContentInit(): void; }
export interface AfterContentChecked { ngAfterContentChecked(): void; }
export interface AfterViewInit { ngAfterViewInit(): void; }
export interface AfterViewChecked { ngAfterViewChecked(): void; }
应用必须实现生命周期钩子。

ng_module.ts文件包含定义angular模块的结构. 一个angular应用是由多个模块组成并通过模块将所有其他模块整合在一起。

NgModuleDecorator显示了NgModule如何绑定其他类。
当我们使用AngularCli创建模板文件时我们可以看到它们的作用。
Core/Profile Feature (core/src/profile)-》暂略
profile目录有以下文件:
● profile.ts
● wtf_impl.ts

Core Reflection Feature (core/src/reflection)-》暂略
reflection目录有一下文件:
● platform_reflection_capabilities.ts
● reflection_capabilities.ts
● reflection.ts
● reflector.ts
● types.ts

Core Render Feature (core/src/render)
angular应用的布局涉及到与angular框架交互的代码,这些代码是应用布局与渲染布局,这两种布局使用rendererAPI。core/src/render/api.ts文件仅定义了这个API。API由以下抽象类组成-RendererType2, Renderer2,RendererFactory2 and RendererStyleFlags2.这个API的实现不在CORE包中.相反,不同platform-x需要为不同的情况提供具体实现。

具有不同呈现需求的场景包括:
● UI web apps in regular browser
● web worker apps
● server apps
● native apps for mobile devices
● testing


3.png

Renderer API是从元素角度出发来定义-提供创建元素,设置元素属性,创建事件监听等功能。
Renderer API不是从DOM出发来定义的.事实上术语"DOM"不在这个API的命名中的任何一部分,(尽管在一些注解中会被提到).使用这种方式,提供什么样子的渲染方式是一个内部的实现细节,如果需要的话可以很容易的更换具体实现。显而易见,对于一个运行在浏览器UI主线程的web应用,这个平台需要在浏览器的DOM(和平台浏览器)的条件下实现Renderer API。但是使用web worker作为替换的话,很可能无浏览器DOM-不同platform下需要提供可使用的渲染方案。稍后我们将会详细探究渲染API的具体实现是如何工作的。
对于render API值得注意的一点是,即使它是使用元素来定义的,it does not list anywhere what those elements are. Elements are identified in terms of string names,but what are valid names is not part of the renderer.Instead, there is an element schema registry defined in the template compiler (<A NGULAR-MASTER>/packages /compiler/src/schema ) and we will examine it further when looking at the template compiler.

现在我们将继续查看renderer API接口. 这个API在一下文件中提供
● <ANGULAR-MASTER>/packages/core/src/render.ts
并且其中包含以下导出内容:
export {
Renderer2,
RendererFactory2,
RendererStyleFlags2,
RendererType2,
/* following are deprecated */
RenderComponentType,
Renderer,
RootRenderer,
}
from './render/api';

我们能够注意到导出中留有命名存在"2"的了内容并且当我们看到实际定义时会发现一些被弃用的render,因此这里不介绍那些弃用内容。如果你浏览旧文档会遇到它们(angular2中存在)。。。

core/src/render目录下只有一个文件:
<ANGULAR-MASTER>/p ackages/core/src/render/api.ts
其中包含了到处都用的到的platform中的render实现。

RenderType2用来标记组件类别,该类别可用来判断需要哪种render,定义如下:
export interface RendererType2 {
id: string;
encapsulation: ViewEncapsulation;
styles: (string | any[])[];
data: {
[kind: string]: any };
}
本质上,createRender()这个主方法用来回答"请根据我所在环境提供一个render方法"这样一个问题。这是借助依赖注入方式灵活渲染的主要前提。
以下有两个案例位置:
● <ANGULAR-MASTER>/ packages/ platform-browser/src/browser.ts
● <ANGULAR-MASTER>/p ackages/platform-webworker/src/ worker_app.ts
这种使用方式的结果对于不同场景下通过依赖注入来提供不同的render。
如果这是RendererFactory2进入依赖注入系统的方式,那么当然,下一个问题是,它是怎么出来的?

以下文件中
● <ANGULAR-MASTER>/packages/core/src/view/services.ts
含有
function createProdRootView(
elInjector: Injector, projectableNodes: any[][],
rootSelectorOrNode: string | any,
def: ViewDefinition, ngModule: NgModuleRef < any > , context ? : any): ViewData {
const rendererFactory: RendererFactory2 =
ngModule.injector.get(RendererFactory2);
return createRootView(createRootData(elInjector, ngModule, rendererFactory,
projectableNodes, rootSelectorOrNode), def, context);
}
which is called from:
function createProdServices() {
return {
setCurrentNode: () => {},
createRootView: createProdRootView,
...
which in turn is called from:
export function initServicesIfNeeded() {
if (initialized) { return; }
initialized = true;
const services = isDevMode() ?
createDebugServices() : createProdServices();
which is finally called from inside:
● <ANGULAR-MASTER>/p ackages/core/src/view/ entrypoint .ts
在NgModuleFactory_.create()方法中:
class NgModuleFactory_ extends NgModuleFactory < any > {
..
create(parentInjector: Injector | null): NgModuleRef < any > {
initServicesIfNeeded();
..
}
}

现在我们将继续来看Renderer API核心类,Renderer2,它是一个抽象类并声明了以下方法:


4.png

5.png

这里仅定义了接口-它们的具体实现要参考不同platform模块下的renderer实现。
renderer是一个简单的抽象,很适合各种各样的渲染引擎。

RendererStyleFlags2最终定义如下
export enum RendererStyleFlags2 {
Important = 1 << 0,
DashCase = 1 << 1
}
该枚举类型被用来提供给Renderer2内的两个方法:
abstract setStyle(el: any, style: string, value: any,
flags ? : RendererStyleFlags2): void;
abstract removeStyle(el: any, style: string,
flags ? : RendererStyleFlags2): void;
core/src/debug:暂不翻译

Core ChangeDetection Feature (core/src/change_detection)
change_detection目录有以下文件:
● change_detection.ts
● change_detection_util.ts
● change_detector_ref.ts
● constants.ts
● pipe_transform.ts
pipe_transform.ts文件定义了PipeTransform接口,管道需要使用该接口:
export interface PipeTransform {
transform(value: any, ...args: any[]): any;
}
constants.ts文件定义了两个变更检测的枚举类型:
export enum ChangeDetectionStrategy {
OnPush = 0,
Default = 1,
}
export enum ChangeDetectorStatus {
CheckOnce,
Checked,
CheckAlways,
Detached,
Errored,
Destroyed,
}
change_detection_utils.ts文件中包括以下内容:
export function devModeEqual(a: any, b: any): boolean {..}
export class WrappedValue {..}
export class ValueUnwrapper {..}
export class SimpleChange {..}
change_detector_ref.ts文件中定义了ChangeDetectorRef类:
export abstract class ChangeDetectorRef {
abstract markForCheck(): void;
abstract detach(): void;
abstract detectChanges(): void;
abstract checkNoChanges(): void;
abstract reattach(): void;
}
change_detection.ts文件中定义如下:
export const keyValDiff: KeyValueDifferFactory[] = [new DefaultKeyValueDifferFactory()];
export const iterableDiff: IterableDifferFactory[] = [new DefaultIterableDifferFactory()];
export const defaultIterableDiffers = new IterableDiffers(iterableDiff);
export const defaultKeyValueDiffers = new KeyValueDiffers(keyValDiff);

不同的子目录下提供了变更检测算法的具体实现:
● default_iterable_differ.ts
● default_keyvalue_differ.ts
● iterable_differs.ts
● keyvalue_differs.ts
Core/Zone Feature (core/src/zone):暂略
Core/Testability Feature (core/src/testability):暂略

Core/Linker Feature (core/src/linker)
Core/Linker功能用来为模板编译器定义API,它对协调编译后的组件共同工作方面是很有帮助的。
当开发者第一次听到Angular中的linker时,可能会立刻想到例如C语言或者其他语言中的linker,但是那些linker与Angular的linker相差很多.记住Angular一直在处理模板语法(页面中嵌入ts逻辑的类似html的呈现形式),该模板需要与ts编写的组件代码一起工作.因此从概念上来讲angular中的linker将应用的不同部分整合到一起(因此使用术语'linker'是专业的说法),但实际上它的工作方式与ANSI C linker方式有很大区别。

Core/Linker Public API
该功能在<A NGULAR-MASTER>/packages/core/src/core.ts文件中导出:
export * from './src/linker';
<ANGULAR-MASTER>/packages/core/src/linker.ts文件列出了如下导出:
// Public API for compiler
export {
COMPILER_OPTIONS,
Compiler,
CompilerFactory,
CompilerOptions,
ModuleWithComponentFactories
}
from './linker/compiler';
export { ComponentFactory, ComponentRef } from './linker/component_factory';
export { ComponentFactoryResolver } from './linker/component_factory_resolver';
export { ElementRef } from './linker/element_ref';
export { NgModuleFactory, NgModuleRef } from './linker/ng_module_factory';
export { NgModuleFactoryLoader, getModuleFactory } from './linker/ng_module_factory_loader';
export { QueryList } from './linker/query_list';
export { SystemJsNgModuleLoader, SystemJsNgModuleLoaderConfig } from './linker/system_js_ng_module_factory_loader';
export { TemplateRef } from './linker/template_ref';
export { ViewContainerRef } from './linker/view_container_ref';
export { EmbeddedViewRef, ViewRef } from './linker/view_ref';

6.png

<meta charset="utf-8">

正如我们所看到的,有一个枚举(COMPILER_OPTIONS),一个方法(getModuleFactory),one type (CompilerOptions),其他导出的都是类.我们注意到在公共API的布局图中没有太多层级。

Core/Linker Usage

core/linker是编译与链接真正的基础API,但是我们将会看到这些类型在别处被使用(事实上,是在angular的Compiler package内的别处). 在源文件中Core/Linker功能一共仅有几百行. 繁重的编译工作是在compiler包中完成的,其源代码很多。例如其中的一个单独的文件view_compiler.ts超过了一千行。我们也可以看到Core/Linker被Compiler-CLI package作为Compiler包中的命令行接口使用。

SystemJsNgModuleLoader类在router模块中使用,定义在ROUTER_PROVIDERS数组中.

router/src/router_module.ts文件内有以下内容:

export const ROUTER_PROVIDERS: Provider[] = [

.. { provide: NgModuleFactoryLoader, useClass: SystemJsNgModuleLoader }

];

Core/Linker Implementation

在core/src/linker中的源文件实现了Core/Linker功能:

● compiler.ts

● component_factory_resolver.ts

● component_factory.ts

● element_ref.ts

● ng_module_factory_loader.ts

● ng_module_factory.ts

● query_list.ts

● system_js_ng_module_factory_loader.ts

● template_ref.ts

● view_container_ref.ts

● view_ref.ts

这些文件中引入了以Ref结尾的类型:

● ElementRef

● TemplateRef

● ViewRef

● ViewContainerRef

● ComponentRef

如果你在使用例如C#这样的语言编程,在该语言中phrase reference type有特定的含义,注意在angular中这不是一个语言概念,而是一个命名约束。这些引用仅仅是属性与方法的收集,它们用来与被引用的结构相互通信。

DOM元素通过ElementRefs暴露在Angular应用中.通常不推荐直接使用ElementRefs,作为一个特定的抽象层级它对angular应用工作在不同的渲染对象上时非常有帮助的。

作为Angular应用开发者,我们创建的模板语法文件经过angular模板编译器编译的为许多的模板refs.如果一个模板有一个简单元素((<p>hello world</p>))那么一个TemplateRef将会被创建.如果使用NgFor之类的指令,那么外部内容将在一个TemplateRef中,而NgFor内部的内容将在另一个模板中。一个TemplateRef被实例化一个或多个时间来创建一个ViewRef。没有必要让TemplateRefs 与ViewRefs之间一对一映射.根据NgFor对应的集合数量将会生成对应数量的ViewRefs,而这些所有的ViewRefs会基于同一个TemplateRef。

视图是一个层次结构,可以使用ViewContainerRef(实际上是一个子视图的容器)插入子视图。视图是层次结构的单元,它向应用程序开发人员提供动态修改显示给用户的内容。因此,请考虑添加和删除嵌入视图,而不是添加和删除单个HTML元素。

ComponentRef包含一个HostView,它可以包含许多嵌入的视图。

现在我们继续查看源代码,从core/src/linker/compiler.ts.文件开始.CompilerOptions为compiler提供了配置项列表(所有属性都为可选的)

export type CompilerOptions = {

useJit ? : boolean,

defaultEncapsulation ? : ViewEncapsulation,

providers ? : StaticProvider[],

missingTranslation ? : MissingTranslationStrategy,

enableLegacyTemplate ? : boolean,

preserveWhitespaces ? : boolean,

};

COMPILER_OPTIONS是一个导出的静态值:

// Token to provide CompilerOptions in the platform injector.

export const COMPILER_OPTIONS =

new InjectionToken < CompilerOptions[] > ('compilerOptions');

CompilerFactory是一个抽象类,它用来通过createCompiler()方法构建编译器:

export abstract class CompilerFactory {

abstract createCompiler(options ? : CompilerOptions[]): Compiler;

}

ModuleWithComponentFactories由NgModuleFactory和ComponentFactory组成:

// Combination of NgModuleFactory and ComponentFactory.

export class ModuleWithComponentFactories < T > {

constructor(

public ngModuleFactory: NgModuleFactory < T > ,

public componentFactories: ComponentFactory < any > []) {}

}

Compiler类用来执行模板编译:

@Injectable()

export class Compiler {

compileModuleSync < T > (moduleType: Type < T > ): NgModuleFactory < T > {.. }

compileModuleAsync < T > (moduleType: Type < T > ): Promise < NgModuleFactory < T >> {.. }

compileModuleAndAllComponentsSync < T > (moduleType: Type < T > ):

ModuleWithComponentFactories < T > {.. }

compileModuleAndAllComponentsAsync < T > (moduleType: Type < T > ):

Promise < ModuleWithComponentFactories < T >> {.. }

clearCache(): void {}

clearCacheFor(type: Type < any > ) {}

}

两个方法clearCache与clearCacheFor都是未实现的方法,其他方法都仅抛出错误。因此,要使用编译器,实际的实现是必需的,这就是独立编译器包的来源。Compiler类是模板编译器类的基础类,这些派生类是实际的模板编译发生的地方。

四个编译方法即可同步编译组件也可异步编译组件,或者是整个NgModule.所有的编译器都把Type<T>作为参数.同步版本会返回一个或者多个工厂的promise,而异步版本会返回可用的工厂方法。

query_list.ts文件定义了通用的QueryList<T>类,它提供了T类型只读数组的控制访问。

ElementRef类用来作为一个实际已被渲染过的元素的引用-它依赖于renderder。

export class ElementRef {

public nativeElement: any;

constructor(nativeElement: any) { this.nativeElement = nativeElement; }

}

通常开发者被建议不要直接使用ElementRef,因为这样做可能导致代码renderer-specific,可能引入安全问题.我们会在文件中提供一些安全性方面的提示。

  • @security Permitting direct access to the DOM can make your application more

  • vulnerable to XSS attacks. Carefully review any use of ElementRef in your

  • code. For more detail, see the Security Guide.](http://g.co/ng/security).)

view_ref.ts文件定义了ViewRef与EmbeddedViewRef抽象类,EmbeddedViewRef抽象类在core/src/core.ts文件中对外暴露,接口InterInternalViewRef用来在core包内部使用。

ViewRef定义如下:

export abstract class ViewRef extends ChangeDetectorRef {

abstract destroy(): void;

abstract get destroyed(): boolean;

abstract onDestroy(callback: Function): any;

}

EmbeddedViewRef定义如下:

export abstract class EmbeddedViewRef < C > extends ViewRef {

abstract get context(): C;

abstract get rootNodes(): any[];

}

InternalViewRef定义如下:

export interface InternalViewRef extends ViewRef {

detachFromAppRef(): void;

attachToAppRef(appRef: ApplicationRef): void;

}

attachToAppRef/detachFromAppRef两个方法是在ApplicationRef文件的attachView和detachView中调用的:

attachView(viewRef: ViewRef): void {

const view = (viewRef as InternalViewRef);

this._views.push(view);

view.attachToAppRef(this);

}

detachView(viewRef: ViewRef): void {

const view = (viewRef as InternalViewRef);

remove(this._views, view);

view.detachFromAppRef();

}

view_container_ref.ts文件定义了ViewContainerRef抽象类。

ViewContainerRef是视图的容器.其中定义了4个getter-元素(容器的锚点元素),injector,parentInjector与length(绑定到容器中的视图数量).它内部定义了两个重要的创建方法-createEmbeddedView与createComponent,这两个方法创建了两个视图的变体(which create the two variants of views supported)。最后内部定义了几个抽象的helper方法-clear,get,insert,indexOf,remove和detach-这些方法工作在视图容器内部的视图中。

export abstract class ViewContainerRef {

abstract get element(): ElementRef;

abstract get injector(): Injector;

abstract get parentInjector(): Injector;

abstract clear(): void;

abstract get(index: number): ViewRef | null;

abstract get length(): number;

abstract createEmbeddedView < C > (templateRef: TemplateRef < C > ,

context ? : C, index ? : number): EmbeddedViewRef < C > ;

abstract createComponent < C > (

componentFactory: ComponentFactory < C > ,

index ? : number, injector ? : Injector,

projectableNodes ? : any[][],

ngModule ? : NgModuleRef < any > ): ComponentRef < C > ;

abstract insert(viewRef: ViewRef, index ? : number): ViewRef;

abstract move(viewRef: ViewRef, currentIndex: number): ViewRef;

abstract indexOf(viewRef: ViewRef): number;

abstract remove(index ? : number): void;

abstract detach(index ? : number): ViewRef | null;

}

createEmbeddedView与createComponent的区别在前者使用template ref作为参数然后穿件一个嵌入的视图,而后者将一个组件工厂作为参数然后使用最新创建组件的宿主视图。

component_factory.ts文件导出了两个抽象类-ComponentRef与ComponentFactory:


7.png

ComponentRef抽象类定义如下:
export abstract class ComponentRef < C > {
abstract get location(): ElementRef;
abstract get injector(): Injector;
abstract get instance(): C;
abstract get hostView(): ViewRef;
abstract get changeDetectorRef(): ChangeDetectorRef;
abstract get componentType(): Type < any > ;
abstract destroy(): void;
abstract onDestroy(callback: Function): void;
}

template_ref.ts文件定义了TemplateRef抽象类和TemplateRef_具体实现类.
export abstract class TemplateRef < C > {
abstract get elementRef(): ElementRef;
abstract createEmbeddedView(context: C): EmbeddedViewRef < C > ;
}

component_factory_resolver.ts文件定义了ComponentFactoryResolver抽象类,它是公共API的一部分:
ComponentFactoryResolver定义如下:
export abstract class ComponentFactoryResolver {
static NULL: ComponentFactoryResolver = new
_NullComponentFactoryResolver();
abstract resolveComponentFactory < T > (component: Type < T > ):
ComponentFactory < T > ;
}
这个文件中也定义了CodegenComponentFactoryResolver,通过
/packages/core/src/codegen_private_exports.ts导出的具体实现类,它在Angular ecosystem中使用很多。

CodegenComponentFactoryResolver定义如下:
CodegenComponentFactoryResolver is defined as:
export class CodegenComponentFactoryResolver implements
ComponentFactoryResolver {
1 private _factories = new Map < any, ComponentFactory < any >> ();
constructor(
2 factories: ComponentFactory < any > [],
private _parent: ComponentFactoryResolver,
private _ngModule: NgModuleRef < any > ) {
3
for (let i = 0; i < factories.length; i++) {
const factory = factories[i];
this._factories.set(factory.componentType, factory);
}
}
4 resolveComponentFactory < T > (
component: { new(...args: any[]): T }): ComponentFactory < T > {
5
let factory = this._factories.get(component);
if (!factory && this._parent) {
6 factory = this._parent.resolveComponentFactory(component);
}
if (!factory) {
throw noComponentFactoryError(component);
}
7
return new ComponentFactoryBoundToModule(factory, this._ngModule);
}
}
CodegenComponentFactoryResolver有一个私有map,_factories 1,它的构造方法接收一个factories数组 2.不要混淆这两个factory!构造方法中迭代factories并为每一个item添加一个_factories中对应的componentType。在它的resolveComponentFactory() 4方法中,CodegenComponentFactoryResolver检查map来匹配factory,if present 5 selects that as the factory and if not, calls the resolveComponentFactory method 6 of the parent, and passes the
selected factory to a new instance of the ComponentFactoryBoundToModule helper
class 7.。

ng_module_factory_loader.ts文件中定义NgModuleFactoryLoader抽象类:
export abstract class NgModuleFactoryLoader {
abstract load(path: string): Promise < NgModuleFactory < any >> ;
}
如果使用懒加载。我们将看在system_js_ng_module_factory_loader.ts文件中看到其实现:
system_js_ng_module_factory_loader.ts定义了SystemJsNgModuleLoader类,这个类中使用SystemJS加载NgModule factories。
// NgModuleFactoryLoader that uses SystemJS to load NgModuleFactory
@Injectable()
export class SystemJsNgModuleLoader implements NgModuleFactoryLoader {
private _config: SystemJsNgModuleLoaderConfig;
构造方法接收_compiler作为可选参数.
constructor(private _compiler: Compiler, @Optional() config ? :
SystemJsNgModuleLoaderConfig) {
this._config = config || DEFAULT_CONFIG;
}

在load()内,如果提供了_compiler则调用loadAndCompile(),不提供则调用loadFactory()。
load(path: string): Promise < NgModuleFactory < any >> {
const offlineMode = this._compiler instanceof Compiler;
return offlineMode ? this.loadFactory(path) : this.loadAndCompile(path);
}

在loadAndCompile()内调用了_compiler.compileAppModuleAsync()
private loadAndCompile(path: string): Promise < NgModuleFactory < any >> {
let [module, exportName] = path.split(_SEPARATOR);
if (exportName === undefined) {
exportName = 'default';
}
return System.import(module)
.then((module: any) => module[exportName])
.then((type: any) => checkNotEmpty(type, module, exportName))
.then((type: any) => this._compiler.compileModuleAsync(type));
}

ng_module_factory.ts文件定义了NgModuleRef and NgModuleInjector abstract classes and the AppModuleFactory concrete class.
NgModuleRef定义如下:
/**

  • Represents an instance of an NgModule created via a NgModuleFactory.
  • NgModuleRef provides access to the NgModule Instance as well other
  • objects related to this NgModule Instance.
    */
    export abstract class NgModuleRef < T > {
    abstract get injector(): Injector;
    abstract get componentFactoryResolver(): ComponentFactoryResolver;
    abstract get instance(): T;
    abstract destroy(): void;
    abstract onDestroy(callback: () => void): void;
    }
    NgModuleFactory用来创建NgModuleRef实例:
    export abstract class NgModuleFactory < T > {
    abstract get moduleType(): Type < T > ;
    abstract create(parentInjector: Injector | null): NgModuleRef < T > ;
    }
    Core/View Feature (core/src/view)
    Core/View功能提供了视图管理.在Angular设计中,一个view就是一个屏幕区域,它展示内容和绑定事件的部分.一个view是一个元素集合.视图通过使用视图容器能够被分层排列.
    <ANGULAR-MASTER>/packages/core/src/linker/view_ref.ts中的注视解释了元素与视图间的关系:
    “视图是应用程序UI的基本构成块.它是元素的最小集合,这些集合一起创建一起销毁.视图中元素的属性能够改变,但是在视图中的结构不可改变.只有使用ViewContainerRef通过inserting,moving与removing方式改变嵌套视图的结构.每个视图可以包含多个View Containers”.
    可以说视图是Angular应用的心脏.Core/View是是一个重要的功能,这个功能是整个核心包的第三以上。
    Private Exports API
    Core/View功能不会在Angular应用中直接使用.Core/View作为Core包的公共API部分不会暴露任何内容,正如我们讨论过的,core/index.ts描述了Core包的公共API,其中一行导出了core/public_api.ts,public_api.ts中到处core/src/core.ts,而这个从视图子目录中没有导出任何内容.
    一些Core/Linker公共导出的类被用来作为Core/View中实现类的基础类.在这个文件中:
    ● <ANGULAR-MASTER>/packages/core/src/linker.ts
    export {TemplateRef} from './linker/template_ref';
    export {ViewContainerRef} from './linker/view_container_ref';
    export {EmbeddedViewRef, ViewRef} from './linker/view_ref';

Core/View用来在Angular包中内部使用.因此我们看到它的导出被定义为以下两个私有导出文件的一部分:
● <ANGULAR-MASTER>/packages/core/src/codegen_private_exports.ts
● <ANGULAR-MASTER>/packages/core/src/core_private_export.ts
第一个文件中有如下视图相关的导出:
export {
clearOverrides as ɵclearOverrides,
overrideComponentView as ɵoverrideComponentView,

  overrideProvider as ɵoverrideProvider

} from './view/index';
export {

 NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR as
  ɵNOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR

} from './view/provider';

第二个有如下导出:
export {ArgumentType as ɵArgumentType,
BindingFlags as ɵBindingFlags, DepFlags as ɵDepFlags,
EMPTY_ARRAY as ɵEMPTY_ARRAY, EMPTY_MAP as ɵEMPTY_MAP,
NodeFlags as ɵNodeFlags, QueryBindingType as ɵQueryBindingType,
QueryValueType as ɵQueryValueType, ViewDefinition as ɵViewDefinition,
ViewFlags as ɵViewFlags, anchorDef as ɵand,
createComponentFactory as ɵccf, createNgModuleFactory as ɵcmf,
createRendererType2 as ɵcrt, directiveDef as ɵdid, elementDef as ɵeld,
elementEventFullName as ɵelementEventFullName,
getComponentViewDefinitionFactory as ɵgetComponentViewDefinitionFactory,
inlineInterpolate as ɵinlineInterpolate, interpolate as ɵinterpolate,

moduleDef as ɵmod, moduleProvideDef as ɵmpd, ngContentDef as ɵncd,
nodeValue as ɵnov, pipeDef as ɵpid, providerDef as ɵprd,
pureArrayDef as ɵpad, pureObjectDef as ɵpod, purePipeDef as ɵppd,
queryDef as ɵqud, textDef as ɵted, unwrapValue as ɵunv, viewDef as ɵvid

} from './view/index';

Core/View Implementation
源文件
● <ANGULAR-MASTER>/packages/core/src/view/types.ts定义了Core/View随处可以使用的帮助类.让我们从ViewContainerData开始,它简单的继承了ViewContainerRef然后添加了一个内部属性来记录嵌套试图的视图数据:
export interface ViewContainerData extends ViewContainerRef {

_embeddedViews: ViewData[];

}

TemplateData接口继承了TemplateRef并添加了一个ViewData数组示例:
export interface TemplateData extends TemplateRef<any> {
// views that have been created from the template
// of this element, but inserted into the embeddedViews of
// another element. By default, this is undefined.
_projectedViews: ViewData[];

}
源文件<ANGULAR-MASTER>/packages/core/src/view/refs.ts中提供了引用的内部实现。
ViewContainerRef_(注意结尾下划线)实现了ViewContainerData进而也实现了ViewContainerRef.
在它的构造函数为锚元素中接收一个ElementData:
class ViewContainerRef_ implements ViewContainerData {
_embeddedViews: ViewData[] = [];
constructor(private _view: ViewData,

             private _elDef: NodeDef,

             private _data: ElementData) {}
get element(): ElementRef {

   return new ElementRef(this._data.renderElement); }
get injector(): Injector { return new Injector_(this._view, this._elDef); }
get parentInjector(): Injector { ..  }
get(index: number): ViewRef|null {.. }
get length(): number { return this._embeddedViews.length; }
createEmbeddedView<C>(templateRef: TemplateRef<C>, context?: C,

   index?: number): EmbeddedViewRef<C> {.. }
createComponent<C>(

     componentFactory: ComponentFactory<C>, index?: number,
     injector?: Injector, projectableNodes?: any[][],
     ngModuleRef?: NgModuleRef<any>): ComponentRef<C> { .. }

insert(viewRef: ViewRef, index?: number): ViewRef { .. }
move(viewRef: ViewRef_, currentIndex: number): ViewRef {..}

clear(): void {..}

}

着两个创建方法实现如下所示:
createEmbeddedView<C>(templateRef: TemplateRef<C>,
context?: C, index?: number): EmbeddedViewRef<C> {

const viewRef = templateRef.createEmbeddedView(context || <any>{});
this.insert(viewRef, index);
return viewRef;

}
createComponent<C>(
componentFactory: ComponentFactory<C>,
index?: number,
injector?: Injector,
projectableNodes?: any[][],
ngModuleRef?: NgModuleRef<any>): ComponentRef<C> {

const contextInjector = injector || this.parentInjector;
if (!ngModuleRef && !

 (componentFactory instanceof ComponentFactoryBoundToModule)) {
ngModuleRef = contextInjector.get(NgModuleRef);

}
const componentRef =

  componentFactory.create(
   contextInjector, projectableNodes, undefined, ngModuleRef);

this.insert(componentRef.hostView, index);

return componentRef;
}

我们可以看到它们之间的区别-createEmbeddedView()调用TemplateRef的createEmbeddedView()方法然后插入由此产生的viewRef;而createComponent()调用组件工厂的create方法,然后带着返回的ComponentRef,插入HostView中.需要注意每个创建方法的返回类型是不同的-第一个返回一个EmbededViewRef而第二个返回一个ComponentRef.

insert, indexOf, remove and detach的实现适当的引用了视图管理API:
insert(viewRef: ViewRef, index?: number): ViewRef {
const viewRef_ = <ViewRef_>viewRef;
const viewData = viewRef_._view;
attachEmbeddedView(this._view, this.data, index, viewData);
viewRef
.attachToViewContainerRef(this);

  return viewRef;
}

move(viewRef: ViewRef_, currentIndex: number): ViewRef {
  const previousIndex = this._embeddedViews.indexOf(viewRef._view);
  moveEmbeddedView(this._data, previousIndex, currentIndex);
  return viewRef;

}
indexOf(viewRef: ViewRef): number {

  return this._embeddedViews.indexOf((<ViewRef_>viewRef)._view);
}

remove(index?: number): void {
  const viewData = detachEmbeddedView(this._data, index);
  if (viewData) {

Services.destroyView(viewData);
}

}
detach(index?: number): ViewRef|null {

  const view = detachEmbeddedView(this._data, index);

  return view ? new ViewRef_(view) : null;
}

ComponentRef_实现类即成了ComponentRef.它的构造函数接收一个ViewRef,这个ViewRef被用来在destroy方法中和用来设置组件的变更检测中和宿主视图中:

class ComponentRef_ extends ComponentRef<any> {
public readonly hostView: ViewRef;
public readonly instance: any;
public readonly changeDetectorRef: ChangeDetectorRef;
private _elDef: NodeDef;

constructor(
     private _view: ViewData,
     private _viewRef: ViewRef,
     private _component: any) {

  super();
  this._elDef = this._view.def.nodes[0];
  this.hostView = _viewRef;
  this.changeDetectorRef = _viewRef;
  this.instance = _component;

}
get location(): ElementRef {

  return new ElementRef(asElementData(
                        this._view, this._elDef.nodeIndex).renderElement);

}
get injector(): Injector { return new Injector_(this._view, this._elDef); }
get componentType(): Type<any> { return <any>this._component.constructor; }

destroy(): void { this._viewRef.destroy(); }

onDestroy(callback: Function): void { this._viewRef.onDestroy(callback); }

}

TemplateRef_实现有一个接收NodeDef和为parent接收ViewData的构造方法.它的createEmbeddedView方法返回一个基于以上参数的新的ViewRef_.
class TemplateRef_ extends TemplateRef<any> implements TemplateData {
_projectedViews: ViewData[];
constructor(private _parentView: ViewData, private _def: NodeDef) {

super(); }
createEmbeddedView(context: any): EmbeddedViewRef<any> {
return new ViewRef_(Services.createEmbeddedView(

                           this._parentView, this._def,
                           this._def.element !.template !, context));

}
get elementRef(): ElementRef {
return new ElementRef(asElementData(

} }

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,565评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,021评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,003评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,015评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,020评论 5 370
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,856评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,178评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,824评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,264评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,788评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,913评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,535评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,130评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,102评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,334评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,298评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,622评论 2 343