欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

Angular 8+ providers在修炼 有大用

在高级语言或者脚本语言中,我们要实例化一个object,一般我们用 new object(),或者java的DI,那么在NG里面一样,我们要使用一个服务,那么就会通过providers来创建或者获取服务的实例,providers现在有多种类型可以选择,

TypeProvider | ValueProvider | ClassProvider | ConstructorProvider | ExistingProvider | FactoryProvider | any[];

ClassProvider :

export interface ClassProvider extends ClassSansProvider {
    /**
     * An injection token. (Typically an instance of `Type` or `InjectionToken`, but can be `any`).
     */
    provide: any;
    /**
     * If true, then injector returns an array of instances. This is useful to allow multiple
     * providers spread across many files to provide configuration information to a common token.
     * 参考拦截器实现
     */
    multi?: boolean;
    /**
     * Class to instantiate for the `token`.
     * 设置注入的对象
     */
    useClass: Type<any>;
}

eg:

@NgModule({
  imports: [
    CommonModule,
  ],
  providers: [
    UtilService, //方式一
    {provide: UtilService, useClass: UtilService},//方式二
  ]
})

其中provide属性作为Injection Token使用,用于定位依赖,用于注册 userClass这个提供商,这个其实就是在后面的程序中使用的服务的名字,他的类型可以是一个BaseClass,也可以是一个InjectionToken

useClass表示我们使用哪一个服务类去创建实例,当然我们可以使用不同的服务类,只要这些服务的类满足我们相应的需求就行,

方式一和方式二一样的功能,在ng官方的例子中列举了一个很详细的例子,参考官方【多级依赖注入】,当描述不同的车辆,宾利和比亚迪虽然都是小车车,但是在大众认知中肯定是两个不同的东西,那么要在代码逻辑如何描述他,看官宣代码:

////////// BCarComponent ////////////
@Component({
  selector: 'b-car',
  template: `
    <div>假如我是BYD,我也车:B: {{description}}</div>
    <c-car></c-car>
  `,
  providers: [
    { provide: CarService, useClass: CarService2 },
    { provide: EngineService, useClass: EngineService2 }
  ]
})

////////// CCarComponent ////////////
@Component({
  selector: 'c-car',
  template: `
     <div>假如我是Bentley,我也车:B: {{description}}</div>
     <div>C: {{description}}</div>
   `,
  providers: [
    { provide: CarService, useClass: CarService3 }
  ]
})

上面CarService作为车这个对象的描述,那么用不同的userClass:CarService2 ,CarService3,当然他们都是继承extends于CarService的,这就非常清楚的描述了屌丝和白富美之间的区别,这个例子就形象描述了Hierarchical injectors这个概念。


并非所有的依赖都是类。 有时候你会希望注入接口,可调用类型,字符串、函数或对象,这个时候InjectionToken上场了

import { Type } from '../type';
/**
 * Creates a token that can be used in a DI Provider.
 *
 * Use an `InjectionToken` whenever the type you are injecting is not reified (does not have a
 * runtime representation) such as when injecting an interface, callable type, array or
 * parameterized type.
 *
 * `InjectionToken` is parameterized on `T` which is the type of object which will be returned by
 * the `Injector`. This provides additional level of type safety.
 *
 * ```
 * interface MyInterface {...}
 * var myInterface = injector.get(new InjectionToken<MyInterface>('SomeToken'));
 * // myInterface is inferred to be MyInterface.
 * ```
 *
 * When creating an `InjectionToken`, you can optionally specify a factory function which returns
 * (possibly by creating) a default value of the parameterized type `T`. This sets up the
 * `InjectionToken` using this factory as a provider as if it was defined explicitly in the
 * application's root injector. If the factory function, which takes zero arguments, needs to inject
 * dependencies, it can do so using the `inject` function. See below for an example.
 *
 * Additionally, if a `factory` is specified you can also specify the `providedIn` option, which
 * overrides the above behavior and marks the token as belonging to a particular `@NgModule`. As
 * mentioned above, `'root'` is the default value for `providedIn`.
 *
 * @usageNotes
 * ### Basic Example
 *
 * ### Plain InjectionToken
 *
 * {@example core/di/ts/injector_spec.ts region='InjectionToken'}
 *
 * ### Tree-shakable InjectionToken
 *
 * {@example core/di/ts/injector_spec.ts region='ShakableInjectionToken'}
 *
 *
 * @publicApi
 */
export declare class InjectionToken<T> {
    protected _desc: string;
    readonly ngInjectableDef: never | undefined;
    constructor(_desc: string, options?: {
        providedIn?: Type<any> | 'root' | null;
        factory: () => T;
    });
    toString(): string;
}
export interface InjectableDefToken<T> extends InjectionToken<T> {
    ngInjectableDef: never;
}

比如我们前端处理HTTP拦截器,

/**
 * A multi-provider token which represents the array of `HttpInterceptor`s that
 * are registered.
 *
 * @publicApi
 */
export declare const HTTP_INTERCEPTORS: InjectionToken<HttpInterceptor[]>;

export class O1Interceptorimplements HttpInterceptor {
   intercept(req: HttpRequest<any>, next: HttpHandler) {
    ///...
   }
   ///...
}
export class O2Interceptorimplements HttpInterceptor {
   intercept(req: HttpRequest<any>, next: HttpHandler) {
    ///...
   }
   ///...
}
export const httpInterceptorProviders = [
    { provide: HTTP_INTERCEPTORS, useClass: O1Interceptor, multi: true },
    { provide: HTTP_INTERCEPTORS, useClass: O2Interceptor, multi: true }
];
通过这种方式,每当发起一个http请求,则自动会执行O1Interceptorimplements.intercept,O2Interceptorimplements.intercept,

比如我们定义一个项目配置文件:

/**
 * 系统资源文件
 */
export interface PrjectSysResource {
  resourceId?: string;
  resourceName: string;
  permission: string;
  close: any;
}
export const DI_SYS_RESOURCE1: PrjectSysResource = {
  resourceId: 't-5205-1',
  resourceName: 'Java 学习-1',
  permission: '',
  close: () => {
    console.log('Java 学习-1');
  },
};
export const DI_SYS_RESOURCE2: PrjectSysResource = {
  resourceId: 't-5205-2',
  resourceName: 'Java 学习-2',
  permission: '',
  close: () => {
    console.log('Java 学习-2');
  },
};
// DI Token
export const SYS_RESOURCE_CONFIG = new InjectionToken<PrjectSysResource[]>('sys.resource.config');

使用:

@NgModule({
  providers: [
    { provide: SYS_RESOURCE_CONFIG, useValue: DI_SYS_RESOURCE1 },
    { provide: SYS_RESOURCE_CONFIG, useValue: DI_SYS_RESOURCE2, multi: true },
    { provide: NZ_WAVE_GLOBAL_CONFIG, useValue: { disabled: false } },
  ]
})
export class CarService4 extends CarService2 {
  constructor(
    @Optional() @Inject(SYS_RESOURCE_CONFIG) private sysResource: PrjectSysResource
  ) {

  }
  getCar() {
    const car = super.getCar();
    car.name = '资源名称:${this.sysResource.resourceName}  Chizzamm Motors, Calico UltraMax Supreme';
    return car;
  }
}

来自  https://zhuanlan.zhihu.com/p/86051678


普通分类: