遅延ロード機能の記述形式変更
URLによって表示するコンポーネントを切り替えるAngularのルーターでは、コンポーネントを初めて表示する時に、そのコンポーネントを含むモジュールをロードする、遅延ロード機能が利用できます。Angular 8では、遅延ロード機能の記述形式が変更されました。
遅延ロード機能について、図4のサンプルで説明します。このサンプルは、画面上部の「First」「Second」「Third」のリンククリック時に、対応するコンポーネントをルーターで切り替えて、画面下部に表示します。
![図4:遅延ロード機能のサンプル(p002-lazyload)](http://cz-cdn.shoeisha.jp/static/images/article/11665/11665_004.png)
「Third」には遅延ロードが設定されており、リンクを初めてクリックしたときに、コンポーネントを含むモジュールを遅延ロードして画面表示します。Webブラウザーの開発者機能で通信内容を表示させると、「Third」リンクのクリック時に、モジュールのJavaScriptファイルが遅延ロードされる様子を確認できます。
![図5:モジュールのJavaScriptが遅延ロードされる様子(p002-lazyload)](http://cz-cdn.shoeisha.jp/static/images/article/11665/11665_005.png)
ルーターの設定は、app-routing.module.tsファイルのRoutes配列に、リスト2の通り記述します。遅延ロードしないコンポーネントは、ルーターのパスをpathに、対応するコンポーネントをcomponentに設定したJavaScriptオブジェクトをRoutes配列に設定します。一方、遅延ロードする場合、従来の記法は(1)の通りでした。loadChildren属性にモジュールのファイルパスとクラス名を文字列で設定します。
const routes: Routes = [ { path: 'first', component: FirstComponent }, { path: 'second', component: SecondComponent }, { path: 'third', loadChildren: './lazy-load/lazy-load.module#LazyLoadModule' } // 従来の記法 ...(1) ];
Angular 8で遅延ロードする場合の記述はリスト3(1)の通りです。importメソッドでモジュールのファイルをインポートして、モジュールのクラス(LazyLoadModule)を設定するようになりました。
const routes: Routes = [ (略) { path: 'third', loadChildren: () => import('./lazy-load/lazy-load.module') .then(m => m.LazyLoadModule) } // 新しい記法 ...(1) ];
従来の記法はモジュールをすべて文字列で記述していたのに対して、新しい記法はJavaScriptコードで記述するため、コードエディターの入力支援を活用できるメリットがあります。なお、新しい記法で利用される、importメソッドを動的に呼び出す記法は「Dynamic imports」と呼ばれます。
Web Workerのサポート
Web Workerは、Webページと独立してバックグラウンドで実行されるプログラムで、CPUパワーを多く利用する、時間のかかる処理を行うのに有効な技術です。Angular 8では、Web WorkerをAngular CLIのコマンドで生成できるようになりました。
Web Workerの利用例を、円周率を計算する図6のサンプルで説明します。計算開始ボタンをクリックすると、計算のループ処理を開始して、その時点で計算された円周率を随時表示します。
![図6:Web Workerで円周率を計算するサンプル(p003-webworker)](http://cz-cdn.shoeisha.jp/static/images/article/11665/11665_006.png)
AngularのプロジェクトにWeb Workerを追加するには、リスト4のng generateコマンドを実行します。生成されたcalc-pi.worker.tsがWeb Workerのファイルです。
ng generate webWorker calc-pi
「計算開始」ボタン押下時にWeb Workerを生成して実行する処理は、app.component.tsにリスト5の通り実装します。
// Workerを生成 ...(1) this.worker = new Worker('./calc-pi.worker', { type: 'module' }); // Workerからメッセージを受信したときの処理 ...(2) this.worker.onmessage = (e: MessageEvent) => { this.calcCount = e.data.count; // 計算回数 this.result = e.data.result; // 計算結果 }; // Workerにメッセージを送信して処理開始 ...(3) this.worker.postMessage(mode);
(1)で、Web Workerのファイルを引数に指定して、Workerクラスのインスタンスを生成します。
Web Workerは生成元(Webページ)とは独立して動作するため、生成元との間でメッセージを送受信して連携させます。(2)はWeb Workerからメッセージを受信したときの処理で、引き渡されてきたMessageEventからデータを抽出して、計算回数countと計算結果resultを取得します。これらはAngularのデータバインディング機能で画面に表示されます。(3)のpostMessageメソッドでWeb Workerにメッセージを送信して、処理を開始します。このとき、計算モードを指定するmode変数をWeb Workerに渡しています。
なお、Web Workerの処理を途中で打ち切るには、this.worker.terminateメソッドを実行します(サンプルでは「計算停止」ボタンクリック時に実行)。
一方、Web Workerのファイルcalc-pi.worker.tsは、リスト6の通り実装します。
// Workerがメッセージを受信したときの処理 ...(1) addEventListener('message', (e: MessageEvent) => { const mode = e.data; // 計算モード var count = 0; // 計算回数 if (mode == 'Mode1') { // ライプニッツの公式 var value = 1; var div = 3; while (true) { value = value - 1 / div + 1 / (div + 2); div += 4; // 一定間隔で円周率の途中計算結果をメッセージ送信 ...(2) if (count % 10000000 == 0) { postMessage({ 'count': count, 'result': value * 4 }); } count++; } } (略) });
Web Workerがメッセージを受信したときに発生するmessageイベントの処理を(1)で実装します。ここでは、イベント引数eのdataプロパティから、計算モードを表す文字列modeを取得して、対応する計算を行います。mode='Mode1'の場合(「モード1で計算開始」ボタンクリック時)は、「ライプニッツの公式(参照:Wikipedia)」で円周率の反復計算を行います。(2)では、反復計算1000万回ごとに、postMessageメソッドで計算内容(回数と計算結果)を、Web Workerの生成元(Webページ)にメッセージ送信します。
なお、このサンプルでは、mode='Mode2'の場合(「モード2で計算開始」ボタンクリック時)に、「ガウス=ルジャンドルのアルゴリズム(参照:Wikipedia)」による円周率の計算を行います。アルゴリズムの詳細はサンプルコードを参照してください。