Skip to content

依赖项

redi 支持以下几种依赖项:

  • 类依赖项
  • 值依赖项
  • 工厂依赖项
  • 异步依赖项

类依赖项

类可以直接作为依赖项:

class AuthService {}

也是可以一个符合 ClassDependencyItem 接口的对象:

export interface ClassDependencyItem<T> {
useClass: Ctor<T>
lazy?: boolean
}

惰性实例化

你可以将 lazy 设置为 true,这样该依赖就不会在它的依赖实例化时被实例化,而是等到实际被调用之后才实例化。

interface IHttpInterceptor {
intercept(): void
}
class AuthHttpInterceptor implements IHttpInterceptor {
intercept(): void {}
}
class FileListService {
constructor(
@Inject(IHttpInterceptor) private readonly httpI: IHttpInterceptor
) {}
request() {
this.httpI.intercept()
}
}
const injector = new Injector([
[FileListService],
[IHttpInterceptor, { useClass: AuthHttpInterceptor, lazy: true }],
])

在上面的例子中,FileListService 依赖了 AuthHttpInterceptor,从注入器获取 FileListService 时该类会实例化,但是 AuthHttpInterceptor 并未实例化:

const fileListService = injector.get(FileListService)

只有实际访问了 AuthHttpInterceptor 方法时才会实例化:

fileListService.request() // -> this.httpI.intercept()

通过延迟实例化部分依赖,可以降低应用初始化时的性能开销。

💡

请确保被延迟实例化的类的构造函数中不存在副作用,否则会导致应用不能按你期望的方式运行。

值作为依赖项

值依赖项是一个符合 ValueDependencyItem 接口的对象:

export interface ValueDependencyItem<T> {
useValue: T
}

该值将会直接被提供给依赖它的依赖。

工厂函数依赖项

工厂函数依赖项将实例化的过程重新交还到开发者的手中,这样就有了更高的灵活性,并且它可以像类依赖项一样声明自己的依赖项。

工厂函数依赖项应当是一个符合下面接口的对象:

export interface FactoryDependencyItem<T> {
useFactory: (...deps: any[]) => T
deps?: FactoryDep<any>[]
}

例子:

interface I18NNumberTranspiler {
transpile(num: number): string
}
const I18NNumberTranspiler = createIdentifier<I18NNumberTranspiler>(
'i18n-number'
)
class ChineseNumberTranspiler implements I18NNumberTranspiler {}
class EnglishNumberTranspiler implements I18NNumberTranspiler {}
class I18NService {
isChinese(): boolean
}
const injector = new Injector([
[I18NService],
[
I18NNumberTranspiler,
{
useFactory: (i18nService: I18NService) => {
return i18nService.isChinese()
? new ChineseNumberTranspiler()
: new EnglishNumberTranspiler()
},
deps: [I18NService]
},
],
]

异步依赖项

有些时候某些依赖并不需要在加载首屏所需 JS 代码的时候加载,因此你可以通过异步依赖项和 webpack 的 import 的函数来懒加载此依赖。此时,该依赖项必须是一个满足 AsyncDependencyItem 的对象:

export interface AsyncDependencyItem<T> {
useAsync: () => Promise<
T | Ctor<T> | [DependencyIdentifier<T>, SyncDependencyItem<T>]
>
}

useAsync 函数必须要异步返回一个已经实例化的依赖项,或者是异步依赖项之外的其他依赖项。同时,声明依赖关系时,声明的并不是对应的标识符,而是 AsyncHook

例子:

// index.ts
interface IReportService {
report(msg: string): void
}
const IReportService = createIdentifier<IReportService>('report')
class OrderService {
constructor(
@Inject(IReportService)
private readonly reportSrvLoader: AsyncHook<IReportService>
)
public order(): void {
// ...
this.reportSrvLoader.whenReady().then((reportSrv) => reportSrv.report(''))
}
}
const injector = new Injector([
[OrderService],
[
IReportService,
{
useAsync: () => import('./reportService'),
},
],
])
// reportService.ts
export default class ReportService {
report(msg: string): void
}