待機中のExtJS 4:動的ローディングと新しいクラスシステム

翻訳者から :有名なExt JS RIAフレームワークのメーカーであるSencha Incは、昨年11月22日に予定されている第4バージョンについて話しました。 約束されたリリースは2月28日に予定されていました。

コミュニティの関心を温めるため(開発者によると、APIは大幅に変更されたため)、「アルファ版またはベータ版の公開」が「数週間以内に」約束されました。 2か月が経過しましたが、まだ約束はありません。

マーケティングのミスがあったことに気づいた-彼らは新製品の発表が早すぎて、そのプレゼンテーションのタイミングを妨げた-開発者は、少しずつチートすることを決め、約束された「ベータ版」をパッケージごとにレイアウトしました。

Ext JS 4の実装でJavaScriptを使用して「アダルト」OOPをエミュレートする試みに特化したフレームワークの公式ブログの最初の記事の翻訳に注目してください。

まず第一に、この記事は以前のバージョンのフレームワークをすでに使用している人にとって興味深いものです-著者は読者がExt JSアーキテクチャに精通していることを期待しています。

Ext JS 4に会う


本日、Ext JS 4の一連のまったく新しい機能の「最初の」機能に注目できることを嬉しく思います。数週間以内に、Ext JSのベータ版をパッケージごとに公開します。 当初、完全なベータ版をこの時期にリリースする予定でしたが、フレームワークの一部は、パッケージを順番に公開することを決めたため、思ったよりもゆっくりと安定しています。 今日は、Ext JS 4のまったく新しいクラスシステムから始めます。

JavaScript言語は、初心者にとっては珍しい「クラス」の概念を最初は提供していませんでした。 Ext JSは、強力なプロトタイピングツールに基づいた独自のクラスシステムを常に備えています。 このソリューションにより、プログラマは開発においてより伝統的なオブジェクト指向のアプローチを使用できます。

Ext JS 4のリリースでは、クラスシステムを新しいレベルに引き上げ、開発を容易にし、柔軟性をさらに高める新しい機能を追加しています。 Ext 4では、構成のクラス宣言、クラスイン、ミキサー、ゲッター、セッター、および依存関係の読み込みという4つのイノベーションが導入されます。



上の図では、新しいクラスシステムのいくつかの利点が注目されています。たとえば、DraggableとResizableは不純物になりました。

クラス宣言


比較のために、Ext JS 3で新しいクラスを作成した方法を見てみましょう。この例では、標準のExt.Windowクラスを拡張するダミーの承認ウィンドウを作成します。

  1. //Ext JS 3.x class definition MyApp. LoginWindow = Ext. extend ( Ext. Window , { title : 'Log in' , initComponent : function ( ) { Ext. apply ( this , { items : [ { xtype : 'textfield' , name : 'username' , fieldLabel : 'Username' } , ... ] } ) ; MyApp. LoginWindow . superclass . initComponent . apply ( this , arguments ) ; } } ) ;
  2. //Ext JS 3.x class definition MyApp. LoginWindow = Ext. extend ( Ext. Window , { title : 'Log in' , initComponent : function ( ) { Ext. apply ( this , { items : [ { xtype : 'textfield' , name : 'username' , fieldLabel : 'Username' } , ... ] } ) ; MyApp. LoginWindow . superclass . initComponent . apply ( this , arguments ) ; } } ) ;
  3. //Ext JS 3.x class definition MyApp. LoginWindow = Ext. extend ( Ext. Window , { title : 'Log in' , initComponent : function ( ) { Ext. apply ( this , { items : [ { xtype : 'textfield' , name : 'username' , fieldLabel : 'Username' } , ... ] } ) ; MyApp. LoginWindow . superclass . initComponent . apply ( this , arguments ) ; } } ) ;
  4. //Ext JS 3.x class definition MyApp. LoginWindow = Ext. extend ( Ext. Window , { title : 'Log in' , initComponent : function ( ) { Ext. apply ( this , { items : [ { xtype : 'textfield' , name : 'username' , fieldLabel : 'Username' } , ... ] } ) ; MyApp. LoginWindow . superclass . initComponent . apply ( this , arguments ) ; } } ) ;
  5. //Ext JS 3.x class definition MyApp. LoginWindow = Ext. extend ( Ext. Window , { title : 'Log in' , initComponent : function ( ) { Ext. apply ( this , { items : [ { xtype : 'textfield' , name : 'username' , fieldLabel : 'Username' } , ... ] } ) ; MyApp. LoginWindow . superclass . initComponent . apply ( this , arguments ) ; } } ) ;
  6. //Ext JS 3.x class definition MyApp. LoginWindow = Ext. extend ( Ext. Window , { title : 'Log in' , initComponent : function ( ) { Ext. apply ( this , { items : [ { xtype : 'textfield' , name : 'username' , fieldLabel : 'Username' } , ... ] } ) ; MyApp. LoginWindow . superclass . initComponent . apply ( this , arguments ) ; } } ) ;
  7. //Ext JS 3.x class definition MyApp. LoginWindow = Ext. extend ( Ext. Window , { title : 'Log in' , initComponent : function ( ) { Ext. apply ( this , { items : [ { xtype : 'textfield' , name : 'username' , fieldLabel : 'Username' } , ... ] } ) ; MyApp. LoginWindow . superclass . initComponent . apply ( this , arguments ) ; } } ) ;
  8. //Ext JS 3.x class definition MyApp. LoginWindow = Ext. extend ( Ext. Window , { title : 'Log in' , initComponent : function ( ) { Ext. apply ( this , { items : [ { xtype : 'textfield' , name : 'username' , fieldLabel : 'Username' } , ... ] } ) ; MyApp. LoginWindow . superclass . initComponent . apply ( this , arguments ) ; } } ) ;
  9. //Ext JS 3.x class definition MyApp. LoginWindow = Ext. extend ( Ext. Window , { title : 'Log in' , initComponent : function ( ) { Ext. apply ( this , { items : [ { xtype : 'textfield' , name : 'username' , fieldLabel : 'Username' } , ... ] } ) ; MyApp. LoginWindow . superclass . initComponent . apply ( this , arguments ) ; } } ) ;
  10. //Ext JS 3.x class definition MyApp. LoginWindow = Ext. extend ( Ext. Window , { title : 'Log in' , initComponent : function ( ) { Ext. apply ( this , { items : [ { xtype : 'textfield' , name : 'username' , fieldLabel : 'Username' } , ... ] } ) ; MyApp. LoginWindow . superclass . initComponent . apply ( this , arguments ) ; } } ) ;
  11. //Ext JS 3.x class definition MyApp. LoginWindow = Ext. extend ( Ext. Window , { title : 'Log in' , initComponent : function ( ) { Ext. apply ( this , { items : [ { xtype : 'textfield' , name : 'username' , fieldLabel : 'Username' } , ... ] } ) ; MyApp. LoginWindow . superclass . initComponent . apply ( this , arguments ) ; } } ) ;
  12. //Ext JS 3.x class definition MyApp. LoginWindow = Ext. extend ( Ext. Window , { title : 'Log in' , initComponent : function ( ) { Ext. apply ( this , { items : [ { xtype : 'textfield' , name : 'username' , fieldLabel : 'Username' } , ... ] } ) ; MyApp. LoginWindow . superclass . initComponent . apply ( this , arguments ) ; } } ) ;
  13. //Ext JS 3.x class definition MyApp. LoginWindow = Ext. extend ( Ext. Window , { title : 'Log in' , initComponent : function ( ) { Ext. apply ( this , { items : [ { xtype : 'textfield' , name : 'username' , fieldLabel : 'Username' } , ... ] } ) ; MyApp. LoginWindow . superclass . initComponent . apply ( this , arguments ) ; } } ) ;
  14. //Ext JS 3.x class definition MyApp. LoginWindow = Ext. extend ( Ext. Window , { title : 'Log in' , initComponent : function ( ) { Ext. apply ( this , { items : [ { xtype : 'textfield' , name : 'username' , fieldLabel : 'Username' } , ... ] } ) ; MyApp. LoginWindow . superclass . initComponent . apply ( this , arguments ) ; } } ) ;
  15. //Ext JS 3.x class definition MyApp. LoginWindow = Ext. extend ( Ext. Window , { title : 'Log in' , initComponent : function ( ) { Ext. apply ( this , { items : [ { xtype : 'textfield' , name : 'username' , fieldLabel : 'Username' } , ... ] } ) ; MyApp. LoginWindow . superclass . initComponent . apply ( this , arguments ) ; } } ) ;
  16. //Ext JS 3.x class definition MyApp. LoginWindow = Ext. extend ( Ext. Window , { title : 'Log in' , initComponent : function ( ) { Ext. apply ( this , { items : [ { xtype : 'textfield' , name : 'username' , fieldLabel : 'Username' } , ... ] } ) ; MyApp. LoginWindow . superclass . initComponent . apply ( this , arguments ) ; } } ) ;
  17. //Ext JS 3.x class definition MyApp. LoginWindow = Ext. extend ( Ext. Window , { title : 'Log in' , initComponent : function ( ) { Ext. apply ( this , { items : [ { xtype : 'textfield' , name : 'username' , fieldLabel : 'Username' } , ... ] } ) ; MyApp. LoginWindow . superclass . initComponent . apply ( this , arguments ) ; } } ) ;


このアプローチは、ほとんどの人にとって馴染みがあり、そのタスクにうまく対処できますが、欠点がないわけではありません。 たとえば、クラスの作成前にExt.Windowが宣言されていない場合、このコードの実行によりエラーが発生し、アプリケーションがクラッシュする可能性があります。 同様に、MyApp名前空間が以前に発表されていない場合も、エラーが発生します。 新しいイデオロギーに従ってクラスが作成されると、これらの問題は両方とも解決されます。

  1. // Ext JS 4.xクラス定義
  2. 内線 define 'MyApp.LoginWindow' {
  3. extend 'Ext.Window'
  4. title 'ログイン'
  5. initComponent function {
  6. 内線 適用 this {
  7. アイテム [
  8. //上記のように
  9. ]
  10. } ;
  11. Myapp LoginWindowスーパークラスinitComponent適用 これ 引数 ;
  12. }
  13. } ;


Ext JS 4では、クラスは名前の文字列表現で参照できます。つまり、上記のエラーは発生しません。 クラスマネージャーは、Ext.Windowが既に宣言されているかどうかを確認するのに十分なほどスマートです。 そうでない場合は、目的のクラスが使用可能になるまでMyApp.LoginWindowの作成を延期します。 フレームワークがすべてを処理できるように、アプリケーションでダウンロードの順序を明確にする必要はなくなりました。

不純物


このシステムの新機能の最初のものは不純物です。 混合物は、名前付きの宣言された一連の動作ロジックと構成パラメーターであり、クラスと「混合」できるため、機能が拡張されます。 不純物を利用するには、クラス宣言にそれらを適用するだけです。

たとえば、クラスのオブジェクトを画面上で移動できるようにするには、ドラッグ可能な混合物をクラスに適用するだけで十分です。 任意の量の不純物をクラスに「ミックス」できます-このようにして、多重継承を実装できます。 これは、ほとんどのJavaScriptフレームワークを使用して長い間達成することが非常に困難であったこととまったく同じです。

不純物は次のように設定されます。

  1. 内線 define 'Sample.Musician' {
  2. extend 'Sample.Person'
  3. ミックスイン {
  4. ギター 'Sample.ability.CanPlayGuitar'
  5. compose 'Sample.ability.CanComposeSongs'
  6. 歌う 'Sample.ability.CanSing'
  7. }
  8. } ;


繰り返しますが、すべてのクラス名は文字列名で相互に参照します-使用済みの不純物がまだロードされていない場合、エラーに遭遇することはありません。 クラスは任意の数の不純物の機能を使用でき、不純物自体は非常に単純です。

  1. 内線 define 'Sample.ability.CanPlayGuitar' {
  2. playGuitar 関数 {
  3. //プレイするコード
  4. }
  5. } ;


設定用の自動セッターとゲッター


Ext JSのほとんどのクラスは、構成オブジェクトをコンストラクターに渡すことで構成されます。 ゲッターとセッターを使用して、構成オブジェクトを変更し、アプリケーションの実行中に編集を適用できます。 Ext JS 4には、これらの機能を使用するときに考慮すべき構成オプションの命名規則ポリシーがあります。 このアプローチにより、開発時間とAPIの一貫性を削減し、ダウンロードしたファイルのサイズを大幅に削減できます。 例を見てみましょう:

  1. 内線 define 'MyClass' {
  2. config {
  3. title 'デフォルトのタイトル'
  4. }
  5. } ;


上記のスニペットでは、titleという単一のカスタムプロパティを持つクラスを宣言しています。 また、このプロパティのデフォルト値も指定します。この場合は「デフォルトのタイトル」です。 Ext JS 4の新しいクラス宣言システムのおかげで、フレームワークは自動的にクラスのゲッターとセッターを作成します。 Ext JS 3.3を使用した場合、定型コードを記述する必要があります。

  1. MyClass = Ext。 extend MyBaseClass {
  2. title 'デフォルトのタイトル'
  3. getTitle 関数 {
  4. これを 返し ますタイトル
  5. }
  6. resetTitle 関数 {
  7. これsetTitle 'Default Title' ;
  8. }
  9. setTitle 関数 newTitle {
  10. これtitle = thisapplyTitle newTitle || newTitle ;
  11. }
  12. applyTitle function newTitle {
  13. //ここにカスタムコード
  14. }
  15. } ;


これで、ライブラリは4つの関数すべてを作成します。 ほとんどの場合、変数の値を更新するだけで十分ですが、構成の変更時に何らかのアクションを実行する必要がある場合があります。 たとえば、クラスがDOM要素でタイトルを表示する場合、次の構成を使用してこの要素を更新できます。

  1. xt。 define 'MyClass' {
  2. extend 'MyBaseClass'
  3. config {
  4. title 'デフォルトのタイトル'
  5. }
  6. applyTitle function newTitle {
  7. 内線 get 'titleEl' 更新 newTitle ;
  8. }
  9. } ;


4つの関数はすべて自動的に作成され、上記のapplyTitleで行ったのと同じくらい簡単にそれらのいずれかをオーバーライドできます。 したがって、クラスで記述するコードが少なくなるだけでなく、ExtJS自体とアプリケーションの両方のサイズが大幅に削減されるため、エンドユーザーがファイルをダウンロードしやすくなります。

動的ローディング


新しいクラスシステムの利点はわずかしかありませんでしたが、先にはさらに興味深いものがあり、後でそれらに戻ります。 しかし、今こそ、Ext JS 4にまったく新しいものを導入するときです: 動的ロード

これまで、Ext JSの任意のバージョンを使用して、開始するにはライブラリ全体をダウンロードする必要がありました。 Ext.Windowクラスのオブジェクトを作成する必要がある場合、クラスを事前に収縮する必要がありました。そうしないと、エラーが発生しました。 Ext JS 4の動的なロードにより、すべてが変更および簡素化されました。

  1. 内線 require 'Ext.Window' 関数 {
  2. 新しい内線 ウィンドウ {
  3. title 「動的にロードされました!」
  4. 200
  5. 高さ 100
  6. } show ;
  7. }


ここでは、Ext JSにExt.Windowクラスをロードし、準備ができたら関数を呼び出すように依頼します。 Ext.requireに配列を渡すことで、任意の数のクラスを照会できます。 実際、それだけです-不可能というだけで、主な魔法は視聴者から隠されています。 Ext JS 4ダイナミックブートローダーはクライアント側でのみ動作し、サーバー側での介入は不要です。 さらに、ロード可能なクラスが持つ依存関係を自動的に解析します。 例として、Ext.Windowを次のようにします。

  1. 内線 define 'Ext.Window' {
  2. extend 'Ext.Panel'
  3. 以下が必要です: [ 'Ext.util.MixedCollection' ]
  4. ミックスイン {
  5. ドラッグ可能 'Ext.util.Draggable'
  6. }
  7. } ;


ライブラリがExt.Windowクラスをロードすると、extend、requireセクション、および不純物の説明で宣言された依存関係を定義します。

必要なクラスのいずれかがまだ宣言されていない場合、フレームワークは最初に依存関係をロードし、次にExt.Windowが宣言されます。 命名規則により、ローダーはクラスごとに適切なファイルを決定する方法を自動的に認識します。 この場合、関数が呼び出される前に次のファイルが要求されます。


ブートローダーは再帰的に動作します-これらのファイルが以前の依存関係に対応していない場合、初期化の準備がすべて整うまでファイルを要求します。

動作モードでは「ファイルごと」モードを使用しないことをお勧めしますが、このアプローチにより、Ext JSを使用する上で最も古くて厄介な瞬間の1つであるext-all-debug.jsファイルなしで実行できます。

最近まで、開発中はext-all-debug.jsを使用し、アプリケーション操作の通常モードではext-all.jsを使用することをお勧めしました。 デバッグバージョンには、ライブラリ全体が読み取り可能な形式で含まれていますが、約60,000行のコードも含まれています。 したがって、すでに修正されているエラー修正プロセスはさらに複雑になります。47657のext-all-debug.js行の例外に関する呼び出しスタックのヒントはほとんど役に立ちません。 一方、ダイナミックローダーを使用すると、問題がsrc / data / JsonReader.jsファイルの56行目にあることがわかります。 そして、すべてのコールスタックと各ファイルの正しい行番号を使用します。

実際、これはアプリケーションのデバッグにおける重要な前進であり、パフォーマンスに問題はありません。ローカル開発では、ライブラリが動的にロードされることに気付くことは非常に困難です。 ブートローダーはデッドロックもチェックし、同期ファイルアップロードと非同期アップロードの両方に使用できます。

あなたが上記を書きたくないなら、心配しないでください。 新しいクラスシステムは、以前のバージョン完全に互換性があります 。 Ext.extendを使用して作成された古いクラスは引き続き機能し、ライブラリ全体を含むext-all.jsファイルを引き続き作成します。

機会のデモンストレーション


非常に簡単なデモアプリケーションを作成し、インターネットに掲載しました 。 例は最も単純なものから始まり、後で徐々に複雑になります。 実際、 サンプルはアーカイブとしてダウンロードして、実験のためにローカルマシンで実行できます。必要なのは、ファイルをアップロードするためのWebサーバーだけです。

新しいクラスシステムは、繰り返し改善されるExtJS 4ライブラリの基盤であり、ライブラリ内の重要な各クラスはより高速になるように更新されているため、開発がより簡単で便利になります。 今後数週間にわたって、Ext JS 4を待って、パッケージの機能を順番にデモンストレーションします。次は、すばらしいデータパッケージです。

Source: https://habr.com/ru/post/J112802/


All Articles