推荐的延迟加载服务类的方法是什么.以下是我的 idea :

创建一个Feature模块foo,其中包含foo.Component.ts,其中foo.module提供服务,服务被注入foo.Component.因此,只有当您导航到foo.Component并且路径定义如下时,服务才会被加载:

App.-routing.mode.ts:

...
const routes: Routes = [
  {
    path: 'foo',
    loadChildren: () =>
      import('./foo/foo.module').then((m) => m.FooModule),
  },
];
...

是否还有其他方法可以延迟加载服务,因为不需要导航到另一个组件?如果我可以在app.Component内单击按钮时调用该服务,就足够了.但是requirement是,那service is only injected/loaded after the button was clicked.

App.Component.ts:

import { BarService } from './foo/bar.service';

@Component({
  selector: 'app-root',
  template: `
    <button (click)="runService()">Run Service</button>
  `,
})
export class AppComponent {
  constructor(private barService: BarService) {}

  runService() {
    this.barService.doSomething();
  }
}

推荐答案

我最近wrote about this岁了.

如果您希望以编程方式延迟加载服务,则需要使用动态导入:const myService = import('./myService.ts')

但通过这样做,您将在测试中受到限制,您将能够模拟该服务.这就是我编写该函数的原因:

export async function injectAsync<T>(
  injector: Injector,
  providerLoader: () => Promise<ProviderToken<T>>,
): Promise<T> {
  const injectImpl = injector.get(InjectAsyncImpl);
  return injectImpl.get(injector, providerLoader);
}

@Injectable({providedIn: 'root'})
class InjectAsyncImpl<T> {
  private overrides = new WeakMap(); // no need to cleanup
  override<T>(type: Type<T>, mock: Type<unknown>) {
    this.overrides.set(type, mock);
  }

  async get(injector: Injector, providerLoader: () => Promise<ProviderToken<T>>): Promise<T> {
    const type = await providerLoader();

    // Check if we have overrides, O(1), low overhead
    if (this.overrides.has(type)) {
      const module = this.overrides.get(type);
      return new module();
    }

    if (!(injector instanceof EnvironmentInjector)) {
      // We're passing a node injector to the function

      // This is the DestroyRef of the component
      const destroyRef = injector.get(DestroyRef);

      // This is the parent injector of the environmentInjector we're creating
      const environmentInjector = injector.get(EnvironmentInjector);

      // Creating an environment injector to destroy it afterwards
      const newInjector = createEnvironmentInjector([type as Provider], environmentInjector);

      // Destroy the injector to trigger DestroyRef.onDestroy on our service
      destroyRef.onDestroy(() => {
        newInjector.destroy();
      });

      // We want to create the new instance of our service with our new injector 
      injector = newInjector;
    }

    return injector.get(module)!;
  }
}

/**
 * Helper function to mock the lazy-loaded module in `injectAsync`
 *
 * @usage
 * TestBed.configureTestingModule({
 *     providers: [
 *     mockAsyncProvider(SandboxService, fakeSandboxService)
 *   ]
 * });
 */
export function mockAsyncProvider<T>(type: Type<T>, mock: Type<unknown>) {
  return [
    {
      provide: ENVIRONMENT_INITIALIZER,
      multi: true,
      useValue: () => {
        inject(InjectAsyncImpl).override(type, mock);
      },
    },
  ];
}

该函数还处理takeUntilDestroyed使用的DestroyRef的用法.

Angular相关问答推荐

not getting circular input switch primeng组件

Angular 17@在大小写时切换多个值

如何用Effect()识别正确的Angular 信号?

为什么我的自定义.d.ts不起作用?LeaderLine不是构造函数

第15角Cookie的单元测试用例

AOS中的数据绑定--可能吗?

在Angular 17的本地服务应用程序时禁用SSR

用于 React 的 ngx-extended-pdf-viewer

Angular 测试被认为是成功的,即使有错误

模块内的命名路由出口 - 路径匹配但内容未加载

如何在对话框angular material内对齐按钮?

带有嵌套表单数组的 Angular react式表单

如何将新的 FormGroup 或 FormControl 添加到表单

来自 ngFor 项的动态 routerLink 值给出错误Got interpolation ({{}}) where expression was expected

Angularmaterial步进器:禁用标题导航

如何在 Angular 2 中创建可重用的动画

实现autocomplete功能

Angular单元测试输入值

找不到@angular/common/http模块

如何在 Angular CLI 6: angular.json 中添加 Sass 编译?