AngularJs。 モジュールの遅延ロード

AngularJsは優れたWebアプリケーション開発フレームワークです。 アプリケーションのビジネスロジックの開発は、DOMをめぐる大騒ぎとは完全に分離されています。 モジュラーは素晴らしいですが、問題の原因でもあります。 モジュールの数は急速に増加しています。 また、ディレクティブはまだアングルUIなどの個別のパッケージにパッケージ化できますが、ビジネスロジックコントローラーではより複雑になります。 セキュリティ要件により、現在のユーザーが利用できないビジネスロジックをクライアントコントローラーにロードすることが原則的に禁止されている場合、すべてがさらに悪化します。 アプリケーションにアクセスするための開発されたロールベースのシステムにより、問題の規模が明らかになります。



Angularには基本的に、オンデマンドでモジュールをロードするシステムがありません。 それでも、javascriptファイルをロードするモジュールを独自に開発できます。 しかし、問題があります。 Angularモジュールを起動するangular.module関数を呼び出すと、Angularの内部構造に機能が追加されません。 また、これは意図的に行われたため、モジュール間の依存関係を観察することなく、任意の順序でスクリプトタグを指定できます。 モジュールの最終的な読み込みは、htmlドキュメントが完全に読み込まれた後に行われます。 実際には、angular.bootstrap関数がこれを行い、インジェクターのインスタンスを作成し、フレームワークの内部構造を初期化します。



そのため、問題が発生します。

  1. ディレクティブを使用してモジュールを確実にロードしてください。 これにより、本当に必要なときにモジュールを正確にロードできるようになります。
  2. 依存関係の解決を提供します。 つまり モジュールに依存関係がある場合は、それらがすべて満たされているかどうかを確認します。 そうでない場合は、依存関係を満たすモジュールのロード手順を開始します。
  3. テンプレート内のディレクティブはロードされるモジュールに依存する場合があり(たとえば、コントローラーを指定する)、モジュールを先にロードする必要があり、その後にのみテンプレートが適用されるため、ディレクティブは指定されたテンプレートがロードされることも保証する必要があります。
  4. さて、もちろん、ダウンロードしたテンプレートのコンパイルとリンク。


始めましょう。

コードに表示されるとホームモジュールのロードが開始されるディレクティブの例:

<div load-on-demand="'home'"></div>
      
      





ロードオンデマンドディレクティブ自体に加えて、ロードするモジュールの名前があります。 このオプションは、ロード可能なモジュールの構成の柔軟性を高めるために選択されました。 通常、設定はmodule.config関数を呼び出すことによって行われます。

関数呼び出しの例:

 var app = angular.module('app', ['loadOnDemand']); app.config(['$loadOnDemandProvider', function ($loadOnDemandProvider) { var modules = [ { name: 'home', script: 'js/home.js' } ]; $loadOnDemandProvider.config(modules, []); }]);
      
      







ここで、ディレクティブに直接渡します。 この場合、ディレクティブを微調整する必要はないため、必要なすべてを実行するリンク関数(linkFunction)のみを返します。 アルゴリズムを示す擬似コード:

 var aModule = angular.module('loadOnDemand', []); aModule.directive('loadOnDemand', ['$loadOnDemand', '$compile', function ($loadOnDemand, $compile) { return { link: function (scope, element, attr) { var moduleName = scope.$eval(attr.loadOnDemand); //   //      var moduleConfig = $loadOnDemand.getConfig(moduleName); $loadOnDemand.load(moduleName, function() { //   loadTemplate(moduleConfig.template, function(template) { //   childScope = scope.$new(); //      element.html(template); //   html  DOM var content = element.contents(), linkFn = $compile(content); //  DOM-   angular linkFn(childScope); //    scope }); }); } }; }]);
      
      







ここで重要なのは、$ loadOnDemand.load()関数の呼び出しです。 スクリプトを構成およびロードするためのすべての機能は、プロバイダー$ loadOnDemandにあります。 それを明らかにします。 コードを煩雑にしないために、実装の詳細を意図的に隠しています。



 aModule.provider('$loadOnDemand', function(){ this.$get = [function(){ //    ,     return { getConfig: function (name) {}, //      load: function (name, callback) {} //   }; }]; this.config = function (config, registeredModules) {} //    });
      
      







各プロバイダーは、サービスオブジェクトを返す$ get関数を提供する必要があります。 このサービスは、必要なときに感染者によって使用されます。 $ get関数に加えて、ビジターはconfig関数を提供します-これはモジュールローダー(上記のapp.config)の構成に使用されます。 実際には、module.config関数はプロバイダーのみを提供するため、プロバイダー構成ロジックを提供するサービスから分離する必要があります。

サービス自体には2つの関数があります。getConfig-構成オブジェクトを簡単に取得するために使用されます。実際、サービスの主な機能はモジュールをロードするloadです。 低レベルのスクリプトの読み込みは、document.createScriptを使用して行われます。このような読み込みは、デバッガIDEにとってより使いやすいです。



そして、水だけを行う必要があります。 しかし、これは機能しません。 その理由は上に示されています-スクリプトがロードされ実行された後、モジュール機能はAngular Infrastructureに配置されません。 したがって、angular.bootstrapに飛び込みます。



DOMがロードされた後、角度の初期化手順が開始されます。 彼女は、アプリケーションのメインモジュールの名前でng-appディレクティブを検索します。 その後、インジェクターが作成され、DOMが角張ったテンプレートにコンパイルされます。 このチェーンでは、モジュールのロード手順(loadModules関数)を起動するのはこの呼び出しであるため、感染者の作成に最も関心があります。 loadModulesは、ベクトルのコマンドのキューである_invokeQueueがあるModuleオブジェクトを受け取ります。 このキューは、angular.moduleが呼び出されたときに作成されます。 このキューの各要素は、機能を追加するすべての作業を行う対応するプロバイダーに与えられます。

既存のプロバイダーを使用してこのアルゴリズムを繰り返すだけです。 インジェクターを使用して取得します。

 aModule.provider('$loadOnDemand', ['$controllerProvider', '$provide', '$compileProvider', '$filterProvider', function ($controllerProvider, $provide, $compileProvider, $filterProvider) { . . . loadScript(moduleName, function(){ register(moduleName); }); . . . }]);
      
      





登録モジュールの登録機能。

 moduleFn = angular.module(moduleName); for (invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) { invokeArgs = invokeQueue[i]; provider = providers[invokeArgs[0]]; provider[invokeArgs[1]].apply(provider, invokeArgs[2]); }
      
      







InvokeArgs [0]にはプロバイダーの名前が含まれ、invokeArgs [1]には新しいサービスを登録するメソッドが含まれます。 invokeArgs [2]-登録メソッドに渡されるパラメーター(注入のリストとサービスのコンストラクター関数)。



おそらくこれですべてです。モジュール名の単純な配列の形式でmoduleFn.requiresにある依存関係を読み込むだけです。 同様のモジュールをプロジェクトに接続すると、メインページは次のようになります。

 <!DOCTYPE html> <html ng-app="app"> <head> </head> <body> <div ng-view></div> <script src="js/angular.js"></script> <script src="js/loadOnDemand.js"></script> </body> </html>
      
      





そして、アプリケーションのメインモジュール、このようなもの:

 (function(){ var app = angular.module('app', ['loadOnDemand']); app.config(['$routeProvider', function ($routeProvider) { . . . }; app.config(['$loadOnDemandProvider', function ($loadOnDemandProvider) { . . . }; })();
      
      







このプロジェクトは、 GitHubでデモを実行します



All Articles