IMPORTANT: 遅延読み込みを機能させるには、読み込むサービスが自動提供されている必要があります。@Injectable({providedIn: 'root'})または@Service()のいずれかで装飾してください。自動提供がない場合、Angularは読み込み後にサービスを構築する方法がありません。
AngularのinjectAsync関数を使用すると、実際に必要なときにのみサービスを読み込むことができます。これは、サービスが大規模なライブラリやめったに使用されない機能に依存しており、初期ページ読み込み時にそのコストを払いたくない場合に便利です。
injectAsyncを使用すると、サービスのコードはバンドラーによって個別のJavaScriptチャンクに分割され、インスタンスを初めて要求したときにダウンロードされます。読み込みが完了すると、Angularは通常のDIシステムを通じてサービスを解決するため、他の注入可能に依存し続けることができ、他のシングルトンと同様に動作します。
サービスの遅延インジェクト
重い表計算ライブラリに依存するReportExporterを想像してください。ほとんどのユーザーはレポートを開きますが、Exportをクリックするのはごく一部です。エクスポーターを必要に応じて読み込みます:
import {Component, injectAsync} from '@angular/core';
@Component({
selector: 'app-report',
template: `<button (click)="export()">Export</button>`,
})
export class Report {
private exporter = injectAsync(() => import('./report-exporter').then((m) => m.ReportExporter));
async export() {
const exporter = await this.exporter();
exporter.export();
}
}
this.exporter()への最初の呼び出しは動的インポートをトリガーし、DIからサービスを解決します。後続の呼び出しは同じPromiseを再利用するため、チャンクは一度だけ読み込まれます。
遅延読み込みされるサービスがデフォルトエクスポートである場合、動的インポートを直接渡すと、Angularが自動的にdefaultを展開します:
@Service()
export default class ReportExporter {
/* … */
}
private exporter = injectAsync(() => import('./report-exporter'));
依存関係のプリフェッチ
デフォルトでは、遅延チャンクは返された関数を呼び出したときにのみ読み込まれます。オプションでprefetchトリガーを渡すことで、ダウンロードをより早く開始できます。トリガーはPromiseを返す任意の関数であり、それが解決されると、Angularはローダーを起動します。
Angularには、ブラウザがアイドル状態になるまで待機する組み込みトリガーであるonIdleが同梱されています:
import {Component, injectAsync, onIdle} from '@angular/core';
@Component({
/* … */
})
export class Report {
private exporter = injectAsync(() => import('./report-exporter').then((m) => m.ReportExporter), {
prefetch: onIdle,
});
}
また、最大の待機時間を指定してonIdleを設定できるため、ビジーなページであっても、プリフェッチは常に一定の期間内に実行されます:
injectAsync(loader, {prefetch: () => onIdle({timeout: 1_000})});
NOTE: プリフェッチは状況に応じて実行されます。プリフェッチが発火する前にユーザーが機能を呼び出した場合、Angularは依然として依存関係を即座に読み込み、準備ができ次第awaitを解決します。
カスタムプリフェッチトリガーの提供
PrefetchTriggerはpromiseを返す単なる関数であり、promiseが解決されるとすぐにローダーが実行されます。ホバーやスケジューラのティックなど、独自のシグナルとプリフェッチを同期させるためにこれを使用します:
import {PrefetchTrigger} from '@angular/core';
export function onHover(target: HTMLElement): PrefetchTrigger {
return () =>
new Promise<void>((resolve) => {
target.addEventListener('pointerenter', () => resolve(), {once: true});
});
}