Gur*_*ofu 5 dependency-injection lazy-loading typescript
框架开发人员喜欢通过实现依赖注入概念来吹嘘。下面的实现是本机的、简单的且类型安全的。
// All below gateways and services are the abstractions
type ApplicationDependencies = Readonly<{
gateways: Readonly<{
category: CategoryGateway;
product: ProductGateway;
}>;
services: Readonly<{
authentication: AuthenticationService;
}>;
}>;
export default abstract class DependenciesInjector {
private static dependencies: ApplicationDependencies | null = null;
public static setDependencies(dependencies: ApplicationDependencies): void {
DependenciesInjector.dependencies = dependencies;
}
private static getDependencies(): ApplicationDependencies {
if (DependenciesInjector.dependencies === null) {
throw new Error("The DependenciesInjector has not been initialized");
}
return DependenciesInjector.dependencies;
}
public static get gateways(): ApplicationDependencies["gateways"] {
return DependenciesInjector.getDependencies().gateways;
}
public static get services(): ApplicationDependencies["services"] {
return DependenciesInjector.getDependencies().services;
}
}
Run Code Online (Sandbox Code Playgroud)
初始化必须在入口点执行:
ApplicationDependencies.setDependencies({
gateways: {
category: new CategoryAxiosGateway(),
product: new ProductAxiosGateway()
},
services: {
authentication: new AuthenticationCognitoService()
}
});
Run Code Online (Sandbox Code Playgroud)
现在这些依赖项可以被注入为
import { Vue as VueComponent, Options as VueComponentConfiguration } from "vue-property-decorator";
@VueComponentConfiguration({})
export default class CategoriesManager extends VueComponent {
private readonly categoryGateway!: CategoryGateway;
// It's O'K from the viewpoint of TypeScript, but this way `categoryGateway` will become to
// reactive field (Vue's 'data') which could be undesirably
// private readonly categoryGateway!: CategoryGateway = DependenciesInjector.gateways.category;
public created(): void {
this.categoryGateway = DependenciesInjector.gateways.category;
}
}
Run Code Online (Sandbox Code Playgroud)
Above approach is enough good for most console and server applications but non-optimal for the fronted applications. It could be a tens of dependencies, and all of them will be immediately initialized once any page of the application will be accessed.
How to solve it? The conceptual answer is "the manipulations with modules dynamic loading" AKA "lazy loading". What I want to ask is could it be implemented without changing of injection method (as demonstrated on above Vue component) and if yes - how?.
Vue Router supports dynamic imports out of the box, meaning you can replace static imports with dynamic ones:
Run Code Online (Sandbox Code Playgroud)import('./views/UserDetails.vue') const router = createRouter({ // ... routes: [{ path: '/users/:id', component: UserDetails }], }) ```
Herewith, the accessing to components does not change.
To load modules on-demand, Nest provides the LazyModuleLoader class that can be injected into a class in the normal way:
Run Code Online (Sandbox Code Playgroud)constructor(private lazyModuleLoader: LazyModuleLoader) {} }
We can not set dependencies by the same way as previous. It will be something like
ApplicationDependencies.setDependencies({
gateways: {
category: async (): Promise<CategoryGateway> => import("@Data/Gateways/CategoryAxiosGateway"),
product: async (): Promise<ProductGateway> => import("@Data/Gateways/ProductAxiosGateway")
},
services: {
authentication: async (): Promise<AuthenticationService> => import ("@Services/Gateways/ProductAxiosGateway")
}
});
Run Code Online (Sandbox Code Playgroud)
Well, it is just the draft. We need to deal with correct typings, default/non-default imports etc. We need to rewrite the DependenciesInjector and ApplicationDependencies also. But how to access these dependencies?
@VueComponentConfiguration({})
export default class CategoriesManager extends VueComponent {
private readonly categoryGateway!: CategoryGateway;
public async created(): void {
this.categoryGateway = await DependenciesInjector.gateways.category;
}
}
Run Code Online (Sandbox Code Playgroud)
I was need make the crated method async.
Could I implement the lazy loading such as keep the above Vue component as it was in the previous example? If no, which the best implementation is possible?
Please note that answer to this topics requires the explanation of the concept, but not the recommendation of the third-partly solution.
我遇到了完全相同的问题,所以我为此编写了 DI lib。奇迹般有效。对我和我的团队来说非常富有成效。
它被调用iti并且有一些很好的 React 绑定,因此应该可以将它们移植到 Vue。
您还可以查看文档中的 React 示例:
https://itijs.org/docs/with-react/react-full#async-request-for-single-item-in-iti
import { createContainer } from "iti"
// blue.ts
// export class Blue implements IColor {}
// rainbow-service.ts
// export class RainbowSegment { constructor(c: IColor) {} }
// async imports, no trace in runtime
export const container = createContainer()
.add(() => ({
blue: async () => {
const { Blue } = await import("./blue")
return new Blue()
},
}))
.add((ctx) => ({
blueRainbowSegment: async () => {
const { RainbowSegment } = await import("./rainbow-service")
return new RainbowSegment(ctx.blue)
},
}))
const blueSegment = await container.items.blueRainbowSegment
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
683 次 |
| 最近记录: |