Code

ラベル AngularJS の投稿を表示しています。 すべての投稿を表示
ラベル AngularJS の投稿を表示しています。 すべての投稿を表示

2016年1月26日火曜日

React.js Vs AngularJS、どっちがいい その3 - React.js 速い!

TL; DR: Web App のスピードにこだわりがあるなら、React.js を使おう。
追伸:新しいプロジェクトが始まる場合、AngularJS 1.0 を使わないで、できれば、AngularJS 2.0 を待ったほうがいいと思います。

 その3で isomorphic (サーバー側レンダリング)を書こうと思いましたが、Reac.js のスピードに驚いたので、まず React.js について詳しくメモしておきたいです。
 今作ってる Single Page Web App のサイズがだんだん大きくなって、ライブラリを除いて、Dev バージョンはつい 15K 行を超えました。一般的に Framework を使うと、アプリのサイズは小さくなります。ちなみに、Dev バージョンの AngularJS 1.3 は約 25K 行、React.js (Flux) は 18K 行ぐらいあります。
  Web App の DOM Node は約 9500 で、メモリは 50M ぐらいを使っています。このサイズで、経験から、AngularJS はもう重くて、Dirty Check と DOM 更新は 400ms 超えることもあります。ユーザーは遅延が感じられるサイズになります。React.js の場合、サクサク動いてて、全然遅いと感じられません。
 Framework 自身のコストもありますので、AngularJS や、Backbone.js などはすぐ DOM を更新する系は重く感じます。React.js の Virtual DOM はかなり快適に動いていることがわかります。
 これは主に shouldComponentUpdate や React.addons.PureRenderMixin うまく使った結果だと思います。
 React.js の場合、Component の state や props が更新されると、render 関数がもう一度呼び出して、Virtual DOM を更新します。さらに更新された Virtual DOM と前の Virtual DOM を比べて、変更された部分だけ DOM を更新します。さっと見ると、AngularJS 1.0 の Dirty Check とあまり変わらないじゃないかと。でも、実際はかなり違います。AngularJS 1.0 は DOM 更新を随時に行います。最初も DOM をスキャンーして、Directive を処理します。メモリなどはかなりのサイズで消耗していきます。React.js の場合、Virtual DOM の比較アルゴリズムはうまく仮想を立てて、shouldComponentUpdate もうまく利用して、本来なら O(n3) ですが、O(n) で実現できるようになりました。つまり、一回の比較で、もう変更点がわかるようになります。Dirty Check は 一回の Digest で2回実行されます。世の中間違って AngularJS を使っているアプリの中に、多分無数の $timeout を使ってるなと思って、Digest はずっと動いているかもしれません。デスクトップはいいとして、モバイルの場合、電池の消耗は速いと思われています。
 
 でも Framework や Lib は使い方次第で、スピードがかなり異なりますので、今のチームでは、うまく PureRenderMixin を使って、state と props を比較して、Component の更新が必要ないなら、shouldComponentUpdate を false を返して、render 関数をスキップします。React.js の中にも false を見ると、その Tree を比較しないようになっています。下記のページもまとめています。
 react.js advanced performance

 Component には Lifecycle があります。なんでもかんでも setState() 関数を呼び出すと、react.js もさすがに重くなります。(前のチーム開発したApp はかなり重く感じられます。React.js でよかったなと思って、AngularJS の場合はもう重くて、重くて、使えないかもしれません。)
 だから、componentDidUpdate や、componentWillReceiveProps 関数の呼び出すタイミングを測って、どのように Parent Component を更新するかとか、新しい props をもらったら、どのように state を変更するかとか細かく考えないと。できるだけ Component 不要な render 関数呼び出しを減らさないと。
 それに、component は本当に state 必要かも考えましょう。必要ないなら、stateless の component を使いましょう。

 AngularJS の機能が強いから、いろんな使い方がありますので、簡単にはアプリ全体の構造が壊されます。($timeout を使って、次の Digest を呼び出して、DOM を更新するという間違った使い方。。。)
 React.js の場合、概念が簡単だし、機能はそんなに強くないから、逆にアプリ全体がきれいに見えます。

 もし、アプリのスピードに要求がある場合、React.js を使った方がいいと思われます。

2015年12月21日月曜日

React.js Vs AngularJS、どっちがいい その2

アップデート 2016/05/22: AngularJS 1.0 に比べたら、React.js のほうがいいです。React.js は UI View のライブラリなので、AngularJS 2.0 と Aurelia と比べるにはちょっと弱いですが、性能重視なら、React.js を使ったほうがオススメです。
 
 先月から、つい新しいプロジェクトが始まって、React.js を毎日使うようになりました。開発してるページは結構複雑なウェブアップで、Back End は ASP.NET C# WebApi を使って、Ajax でデータを取得してから、すべてのロジックは Client サイドにあります。
 今全てのページも一つの App にして、実際レンダリングは JavaScript になっています。それも React.js の哲学の一つ:DOM は遅い、JavaScript は格段に速い。あと、AngularJS のテンプレートと違って、Component が JSX で JS コードで直接 HTML をコントロールしています。
 JS コードだから、何をやろうとすると、結構やりやすいです、テープレートに比べたら。ただ、JSX を普通の JS コードに変更するにはちょっと時間がかかります。今 WebPack と Babel を使っています。Gulp Watch を使って、JSLint も含めて、コンパイルは約 3 秒ぐらいかかります。これは遅いと感じています。AngularJS の場合、コンパイルが必要ないから、スタイリングするとき、やりやすいです。WebPack を通すと、ちょっと時間がかかるため、Watch をうまく使わないと、開発効率が下がります。今、Gulp のタスクをさらに細かくにして、コンパイル時間を1秒いかに抑えたいです。ここで、AngularJS の開発効率は高いと思います。

 次は Flux という Framework です。AngularJS の場合、テンプレートから、Service まですべての MV* を提供しています。React.js は UI Library だから、Flux とうまく合わせて、一つの Framework になります。Flux は結構簡単なもので、何かをやろうとすると、AngularJS と比べたら、やりにくく感じます。ただ、Flux は簡単ゆえに、アプリ全体の構造も簡単になります。AngularJS みたいに、2ヶ月ぐらい勉強時間と比べたら、React.js のほうが勉強しやすいし、強制的に簡単なアプリ作れます。ここで、React.js がいいなと思います。AngularJS の機能は時々複雑すぎて、理解するには時間がかかります。

 最後パフォーマンスについて。どんな Framework を使っても、それなりのコストが発生します。勉強時間とか、Framework のロード時間とかいろいろ。ただ、Framework を使うと、開発の効率も向上するし、Unit Tests と End-2-End Tests のツールも簡単に使えるようになります。そこは総合的に考慮しなければなりません。
これがいいですね: The Cost of Frameworks
 自分の感じでは、React.js は 3-4 倍ぐらい、AngularJS より速いです。DOM のレンダリングスピードがそこまで速いと感じたら、AngularJS 好きな私も、さすがに考えます。100ms の React.js と 300ms の AngularJSの差、200 ms は大きいです、End user の視点から見ると。
 ただ、React.js も万能じゃないので、Virtual DOM のツリーを毎回比べるので、App が大きくなると、遅くなります。
 React のパフォーマンス

 隣のチームでは AngularJS と React.js を同じプロジェクトに使おうとしていますが、Architect が反対しているそうです。理由として、二つの技術を混ぜたくないです。将来メンテナンスに難があると考えてるでしょう。。。私は両方をうまく使い分けしたほうがいいと思って、混ぜるのが賛成ですけど。

 今、私に AngularJS と React.js どっちがいいと聞かれると、アプリの性質や、開発期間とかによって、両方を使いたいなと思います。。。
 個人的には React.js の Component が AngularJS の Directive より使い易いと思います。もし会社全体的に React.js を使うなら、WebPack を使って、Component を充実したら、AngularJS より使い易いと思います。

AngularJS 2.0 も Lazy Loading などできたら、どっちを使うかまた悩むところです。。。

 あ、もう一つ、現在 AngularJS のライブラリが多くて、成熟していますが、React.js の場合、まだまだ発展途中で、NPM からインストールした Component にはバグがあったり、機能面ちょっと足りなかったり部分があります。もし、複雑な Web App を開発するなら、AngularJS のほうがいいかもしれません。

 まぁ、後日経験を積んで、また比べましょう。

追伸: React.js には isomorphic 機能がサポートしています。いわゆる、サーバー側もクライアント側も同じコードで Web App をレンダリングできます。つまり、サーバー側も同じ JS コードで、まず Web App の HTML をレンダリングして、その HTML コードがクライアント側でロードして、同じ JS コードを実行すると、イベントハンドラーや、ルートなども初期化して、Web App が動くようになります。これは Web App のロードスピードをかなり加速できます。
 サーバー側、Node.js を使うなら、簡単にできますが、Facebook がいろんな言語を対応しているそうです。こちら ASP.NET バージョンです:
 reactjs.net

 今のプロジェクトでは、isomorphic 使ってないので、来年早々やってみようと思っています。
 では、また。

2015年7月30日木曜日

React.js と AngularJS、どっちがいい?

 追加:下記は React.js 実際使う前の書き込みです。こちらも:
 React.js Vs AngularJS、どっちがいい その2
 React.js Vs AngularJS、どっちがいい その3 - React.js 速い!
 
 最近、隣のチームのプロジェクトでは AngularJS がヘビーだから、 React.js にしたと聞きました。最初、そのチームは AngularJS を使って、Demo を作りました。モバイルでテストすると、何かウェブサイトがすこし応答が遅いと思ったそうです。でも、それは AngularJS の問題ではないと思います。実際向こうのデモサイトを見てみたら、$timeout() がいっぱいあったりして、Directive もいっぱい作って、本来計算が終わったら、$apply を使うべきところを全部 $timeout を使ったりしていました。Angular の使い方としては間違ってると思います。Dirty Check はただ Model 変化をチェックする方法の一つです。Getter Setter の中にいろいろ判断するより、Dirty Check は理解しやすいし、重い処理は Framework に譲れたと思われています。
 まぁ、そのチームが React.js に乗り換えったら、Flux を使って、プログラム全体の構造は3年前 Backbone.js を使った時とほぼ同じになりました。実際デモサイトと比べると、それほど速いと思われてないし、勉強とか、Cross Browser の対応とか、またいろいろ苦労したそうです。最初デモサイトがモバイルでは重いと思われたことは 300ms Click との関係もなくはないと思います。
 しかも、React.js を使ったら、プログラム全体がわかりづらくなりました。Flux の Dispatcher を理解しない限り、どこで、何が更新されたかさっぱりわかりません。。。
 逆に AngularJS だったら、Controller, Service とかすぐ見つかるし、Back end の開発者もある程度見ればわかります。
 多分、区別はそこだと思います。React.js は Framework というより、ライブラリだと思います。つまり、アプリとみなすには、Flux などイベント Dispatcher、Model などをまた作らなければなりません。それを考えてみると、Polymer のほうが使い易いと思いますし、速度的には React.js の Virtual DOM より、それほど遅くないと思います、どうせメモリ上の比べだから、Dirty Check でも。
 将来 AngularJS 2.0 をかなり期待できると思います。Polymer とのシームレスとか、遅延ロードとか、Framework としてはかなりいいフィーチャーになります。
 
 まぁ、まだ React.js を詳しくみてないから、こう思ってますが、実際 React.js を View にして、AngularJS の Framework に組み込んだら、面白いかもしれません。
 今のプロジェクト一段落したら、また React.js を使ってみて、AngularJS と比べたいと思います。
 それでは。今現在の考えで。

2015年4月19日日曜日

AngularJS Directive の使い方

 おととい別チームの Front End Dev に Directive のオーダーについて聞かれました。そのプロジェクトでは ng-model の隣に、入力値のチェックやフォーマットを全て個々の Directive で行われています。いっぱい Directive が書かれていて、コードを読むにはちょっと大変です。。。それで、問題となってたところは二つ Directive の中に、onblur を使って、入力値をチェックしたり、値を変えたりしてました。ただ、onblur のコールオーダーによりページには変な動作になりました。それで、onblur の handler の呼び順番変えられるかと聞かれました。
 少し、彼らの Directives を見てみると、あまりいいアプローチと思ってませんでした。なぜなら、priority も設定してないし、ng-model の中に formatter と parser キューがありますので、本らなら、それを使って、すぐできる機能なのに、全て onblur の中に書いてしました。
 まぁ、一番大事なのは問題を解決するので、まず、directive に priority という属性がありますので、それを使って、direcitive の link function を実行するオーダーが変更できます。具体的に言うと、AngularJS はまず一つの element に attach した全ての directive を array に入れて、そのあと、priority を使って、Sort してから、link を呼び出してます。それで、directive の onblur を呼ぶ順番は変えられます。
 まぁ、もう一つの方法は $timeout を使って、次の digest circle に実行することです。ただ、これは間違いだと思っています。$timeout はあまりにも使いすぎてる感じがあります。何か動かなかったら、すぐ $timeout を呼ぶとか。。。
 注意すべきところは $timeout では、$rootscope.apply() が呼ばれているので、全てのあたりが一回 digest されます。もし複数の $timeout が呼ばれるなら、ページはずっとリフレッシュされます。。。これは AngularJS が重いと言われた原因の一つだと思います。

 今回なら、ng-model すでに formatter と parser があるので、それを使うべきだと思います。それに、一つの機能を一つの directive に入れるのはあまり良くないです。いっぱい directive になると、さらにその中に jquery などを使って、DOM 操作すると、オーダーが難しくなります。もし、単独の directive を使うなら、カテゴリにより機能をまとめるべきです。例えば、入力値のフォーマットをチェックするなら、全てのチェックの一つの directive にまとめた方がいいです。そうすると、$validate でエラーメッセージを設定には簡単になります。表示の順番も操作しやすくなります。
 
 本来なら、Framework は裏でいっぱいやっているので、その処理を知るべきだと思います。例えば、directive の compile、link function はどのように呼ばれているかとか、angular の bootstrap はどのように実行しているかとか。それを知らないと、パフォーマンスのいいアプリは作れるには難しいです。
 
 それでは。

2014年10月31日金曜日

IE8 AngularJS & jQuery ui - problem -> ng-non-bindable の使い方

 昨日、隣のチームから変なバグが聞かれました。具体的に、jQuery ui の datepicker が IE8 では動かなくなった。まぁ、最新版の AngularJS は IE8 サポートしてないから、問題ないけど、今のプロジェクトでは 1.0.8 を使ってるし、IE8 もサポート対象ブラウザーなので。。。あ〜頭が痛くなる。。。
 jQuery の datepicker のサープルを IE8 で開いて、動きは正しいようです。多分、AngularJS と jQuery ui の間に何か干渉が起きたと思われました。HTML を見てみたら、各日付の <td> tag 中の <a> に <!-- IE fix --> コメントが追加されたことが気づきました。AngularJS には <a> tag を IE8 での特別処理が入ってるようです。
       // add a comment node to anchors to workaround IE bug that causes element content to be reset
      // to new attribute content if attribute is updated with value containing @ and element also
      // contains value with @
      // see issue #1949

つまり、AngularJS は上記の IE fix コメントを追加したのです。一般的なライブラリは innerHTML を使って、タグの内容を取得すると、その IE fix も一緒に取得されるのです。parseInt などを使うと、エクセプションが throw されます。本来数字のみ入っている場所に他の文字列が入ったので、何か起きると、不思議ではない。
 
 もう少し調べてみたら、Angular は ng-non-bindable という directive を提供しています。これを使うと、 Angular は HTML DOM をスキャンする時、そのブロックをスキップさせます。つまりその中にある要素は Angular の $digest サイクルに入らない。
 これで、Angular は勝手に <a> tag 何かを入れることがなくなります。問題解決。

 今後 IE 8 をサポートしている間、気をつけないと。
 それでは。

2014年10月18日土曜日

Protractor での自動テスト

 先週から、検証チームを助けて、Protractor での自動テストが始めました。先日ダウンロードして、インストールしようと思ったんですけど、npm がなぜかshanum エラーが出ました。調べたら、ネットワークのせいかもしれないと、もう一回インストールして、無事成功しました。
 Protractor を動かすには、まず Selenium サーバーを起動して、config ファイルにそのアドレスと、spec の場所を入れて、後、Jasmine sytax での spec が必要です。
 Protractor とともに、webdriver-manager と言う Node のコマンドがインストールされます。webdriver-manager update を実行すると、google から chromedriver.exe, IEserverdriver.exeと、Selenium jar ファイルがダウンロードされます。その後、webdriver-manager start で selenium サーバーが起動されます。Jetty なんちゃら 4444 がコンソールに表示されたら、起動成功。
 その後、config に下記の JSON を記入して、spec を書いて、すぐ実行できるようになります。
exports.config = {
  seleniumAddress: 'http://localhost:4444/wd/hub',
  specs: ['todo-spec.js']
};
spec のサンプル:
describe('angularjs homepage todo list', function() {
  it('should add a todo', function() {
    browser.get('http://www.angularjs.org');

    element(by.model('todoText')).sendKeys('write a protractor test');
    element(by.css('[value="add"]')).click();

    var todoList = element.all(by.repeater('todo in todos'));
    expect(todoList.count()).toEqual(3); browser.sleep(3000);
    expect(todoList.get(2).getText()).toEqual('write a protractor test');
  });
});
protractor conf.js を実行すれば、angular のウェブページが表示されて、TODO に自動的に一つアイテムを追加されて、その後、 TODO の数をチェックして、終了。

 注意すべきところは、protractor は selenium のラッバーみたいなもので、AngularJS 終了を待ってから、コマンドを実行してます。(おそらく、Angular の phase をチェックしてるかもしれない)、もし、ウェブページに Angular がなければ、変なエラーが出るのです。原因は protractor ずっと待ってて、待ち続けて、タイムアウトになります。
 このとき、browser.get や element などが使えなくなります。browser.driver を使うべきです。browser.driver は webdriver js で、findElement などが使えます。この時、適当に sleep を入れて、JS の実行完了や、ajax の実行などを自分でまつ必要になります。。。
 やはり、protractor が使いやすいですね。
 
 後日、また続きを。それでは。

2014年9月8日月曜日

Angularjs $timeout 調べ

 DI (Dependency Injection) は Javaや、ASP.NET などバックエンドには人気ですけど、AngularJS はそれを JavaScript に応用できるようにしました。具体的に言うと、モジュールをロードするときや、関数を呼び出す場合、$injector の invoke 関数で、呼び出す対象の引数を全部パースして、providerと instance キャッシュの中に探して行く、もし同じ名前の対象があったら、それを使います。
 さらに、Ajax call を実行するとき、$http と $httpBackend を利用することで、$browser も内部で持つことで、すべての操作をライブラリ内部で intercept できるようになります。
 この中に、面白いのは $timeout というものです。実際の timeout 関数は既にあるのに、何で $timeout を実装するのか?
 理由としては、二つあります。まずは Unit test を書くとき、自分で timeout をトリッガーできるようになります。実際のコードを見ると、promise を使っていますが、promise の中には、window.timeout 関数が使われています。これで timeout を同じ機能が実行できるようになります。さらに、もし外部で同じ promise を resolve したら、同じ関数が呼ばれますので、timeout 発生時と同じ動作になります。これはかなりいいことです。もう timeout を待つ必要がなくなります。
 もう一つは Angular Scope の $digest に関係あります。$timeout の中に $rootScope.apply() が呼ばれています。これを理解するには JavaScript 実行のサイクルを理解する必要があります。以前では setTimeout(function() {}, 0) を呼び出すことで、今までの JavaScript コールスタックをすべてクリアした後に、コードを実行する方法があります。$timeout も同じです。AngularJS に自分のサイクル、いわゆる $digest がありますの、この関数ですべての watcher を oldValue, newValue を計算して、listener をその後呼び出します。一つのサイクルを終わらないと、Angular は対象の変更が察知できないことがあります。例えば、ng-include でテンプレートの path を変更したい場合、関数の中に
    /* templateUrl の値は abc とします。*/
    templateUrl = "";
    /* その他の操作*/
    templateUrl = "abc"; // テンプレートをリロードしたい
をやると、$digest はこの関数終わった後に実行されますので、templateUrl は変更してないように見えます。つまり、変数の変更をAngularJS に察知させる為に、一つの $digest サイクルの終わりを待つ必要があります。このとき、$timeout は利用すれば、ちゃんと意図通りできます。
     templateUrl = "";
     /* 他の操作 */
     $timeout(function() {templateUrl = "abc"})
これで、最初の templateUrl がクリアされて、$digest の実行で、ng-include directive がクリアされます。その後、次の $digest サイクルで、templateUrl がまた元に戻したので、すべての expression がもう一度更新されます。
 もちろん、自分で setTimeout を実行して、scope.apply() を呼び出しても、同じ機能ができますの、そのショートカットとして、$timeout を使えば、簡単になります。
 
 まぁ、dirty check にはいろいろ不利なところもありますが、Knockout.js の set 関数を比べると、自分は Angular のほう好きです。
 最近、このライブラリも人気だそうです:
    durandal
   このライブラリは require.js を使っていますので、Angular でできない遅延ロードもできます。聞いたことですが、テンプレートのほうも Angular よりちょっとだけ優れています。
 まぁ、これらは Angular 2.0 で改善される予定なので、少し待ってもいいような気がしますけど。
 
 それでは。

2014年7月24日木曜日

WCF + Angular で Sever と Client の Decouple

 最近、C# ASP.NET に突入。Back end は C# ASP.NET で、Front End は主に AngularJS を使います。以前 Microsoft の Web Application サンプルはほとんど knockout.js を使っていたため、古いシステムはほとんどそれでした。が、AngularJS から Dependency Injection などのデザインパタンが導入されて、Unit Test や End to End Test が簡単にできるようになったので、だんだん AngularJS に移行する動きがあります。
 今のプロジェクトも移行中です。新しい Web Site は全部 Responsive Design を使っていて、AngularJS ベースに作っています。ただ、やはり cshtml の中に C# Razor のコードと HTML コードがごちゃごちゃになって、みにくいです。それで、WCF を使って、JSON オブジェクトを Front End に返して、View に関してのすべてのロジックは AngularJS をベースに JavaScript で実装することはいいような気がしてます。
 まず、Action を WCF の End Point に変更して、Model はそんなに大きくないので、$http を使って、AJAX でロードして、その後、もう Front End の世界です。新しいブラウザだと、もっと速いような気がしています。サーバーの負荷を考えると、もっと低いような気がしてます。なぜなら、View の parse が必要なくなり、すべて C# コードになるからです。 Ajax コールが多くなりますが、データを組み立てるだけなら、全然軽いと思います。
 Front End でも、Dependency Injection を使っているので、サーバーと隔離するできるし、サーバー側もデータをメインでテストできるから、すべてはスムーズに分けるようになります。Decouple も MVC だけでなく、Server と Client の間でもできるようになります。
 これは多分いいことです。次回の会議でちゃんと話しましょう。
 それでは。

2014年7月15日火曜日

AngularJS Scope と $apply

 今日時間ができたので、Angular の動きをちょっと追ってみました。module の登録は一つの難しいところですし、injector という概念も難しいと思います。ただ、実際使うとき、Scope というのはかなり重要です。
 基本的にAngularJS は Compile 段階で、必要に応じて、Scope を作ります。さらに ng-scope というクラスを該当要素に追加されます。Scope を取得するには、angular.element(el).scope() で scope object が取得できます。ng-app の要素に対して、rootscope が作られます。
 Scope は一つの object ですので、その prototype 中に、$apply という関数はあります。これはどういうとき使うかというと、Angular の世界に何かイベントを引き起こす時使います。イベントを引き起こすというのは model を変更したり、メッセージを $emit, $broadcast したりする場合です。
 さらに遡ると、JavaScript の中に、イベントハンドラーは、jQuery の proxy などの bind 関数を使わない限り、基本的に window Scope で実行されるので、window Scope は Angular の Scope と違うため、単純にその中のでデータを修正したりすると、Angular の $digest 処理が実行されません。そうすると、$watch のデータのリフレッシュなどは Angular が検知できなくて、画面のリフレッシュもできません。
 一つの例として、もし directive の link 関数で、要素に何かイベントハンドラーを bind したら、さらにこのイベントが発生したことを、 Angular の世界にそれを通知する場合、該当要素の Scope を取得して、$apply 関数を呼び出す必要があります。
    if (ctrl.$viewValue !== value) {
      scope.$apply(function() {
        ctrl.$setViewValue(value);
    });
 
 実際のソースコードを見てみると、Angular は compile 段階で、HTML のテンプレートを保存したり、$$watcher に expression を追加したりしています。その後、 link 関数を返して、呼び出されます。その link 関数の中では、イベントハンドラーの追加や、jQuery UI の呼び出すことなどができます。さらに、何か変化がありましたら、Scope の $apply が呼び出されますので、 Angular の loop に入って、HTML のリフレッシュが実行されます。
 例えば、ng-model directive の実行順番は:
 Angular が bootstrap するとき、すべての directive を compile して、link 関数を呼び出します。このとき、ng-model の入っている要素の change イベントにイベントハンドラーをバンドルされます。キーボードのキーを押したとき、この change イベントが発生しますので、ハンドラー関数が呼び出されます。
 その後、 interpolation がこの directive を $watch リストに追加します。-> すべての directive とモジュールを初期化完了したら、Angular の loop から抜き出します。

 もしユーザーが何かのキーを input に押したら、ng-model のイベントハンドラーが呼ばれて、$apply 関数で model の value を変更します。
 $apply 関数の中に $digest 関数が呼ばれて、すべての登録した $watch 関数を一通り実行されます。
 これが終わったら、interpolation が実行されますので、HTML の変更などが実施されます。
 次、キーを押したイベントハンドラーの実行が終わりますので、Browser がリフレッシュされます。
 
 ちょっと複雑のように見えますが、実際どの directive もこのようなループが実行されます。一つ理解すれば、Angular はどのように動くかはたいてい明確になります。
 それでは。

2014年6月15日日曜日

AngularJS: なぜ {{name}} を使うか

 最近、同僚に AngularJS で何で {{}} を使うところと使わないところがあるかと聞かれました。まぁ、簡単に答えました:ng-model などの Directives では Angular Framework はそれをわかっているので、{{}} で示す必要がないです;ただ、HTML String の中で、どれが Static 、どれが AngularJS の $watch 対象か、区別をつくために、{{}} を使う。

 それは基本的な Angular Framework の作りで決まっています。Angular では ng-app や、 ng-click などすでに提供した Directives がありますし、それ以外 {{}} で変数を $watch するところ、$apply で処理する String があります。Scope にその値を探したりする必要がありますので、{{}} を使うようになりました。
 これは基本的な Handlebars などのテンプレート Lib も似たようなものです。

 今日簡単に書いて、時間があったらまた詳細をまとめよう。

2013年12月11日水曜日

AngularJS コンセプトから

 最近 AngularJS Frameworkを勉強しながら、web app を作っています。jQuery や、backbone.js, ember.js, knockout.js などのライブラリと違うタイプで、使いこなすまで、ちょっと時間がかかるかもしれません。ember.js もそうですけど。。。
 ただ、ある程度慣れると、開発のスペードは結構あがりますので、損はないでしょう。

 コンセプトから:
 jQuery は 主に DOM を操作するためのライブラリで、AngularJS は MVVM の Framework です。ライブラリは Function を呼び出すことで、機能を実現しますが、 Framework だと、"Don't call me. I will call you." 式になります。つまり、自分は部品を提供して、Framework がそれを呼び出して、機能を実現します。
 AngularJS をがロードされるとき、まず ng-app という directive を探して、compile されます。されに、その下のすべての ng- から始まった core directive や、自分で登録した directive をスキャンされて、scope を作ります。その後、controller が初期化されて、このとき、controller にあった model, viewModel が初期化されて、link されます。すると、ウェブページが表示されるようになります。
 この過程はかなり複雑ですし、各 directive も違うし、操作 Queue の作りも簡単ではありません。こちらのコードは今まで読んだ JS code の中で神様の領域に入るような気がします。:)まぁ、結構かみコードは結構ありますけど。
 通常の DOM 操作より、AngularJS は two-way data binding で Developer を複雑、面倒なデータアップデート処理から解放して、機能やアーキテクチャーに集中させるようになります。
 
さらに、$injector で Dependency Injection を他の Framework から導入されます。そうすると、Unit test や automatic integration test も大変簡単になります。例えば、service に provider, factory を定義して、違うデータソースからデータを取得して、上の Controller がそれに何も知らなくても、ただ関数を呼ぶだけなので、レイアの Decoupling が実現されました。

あと、$filter や、directive も自分で定義できるし、ng-include で template のサポートもできます。handlebarsよりわかりやすいし、機能的にはかなり面倒な、簡単な部分をカバーしています。

まぁ、一般的な Web App だったら、 jQuery が十分だと思いますけど。例えば、ボタンで表示部分の変更、Drop down リストの変更などは AngularJS を使うより、jQuery のほうが速いし、簡単です。underscore.js などのライブラリと一緒に使うと、便利です。
もし、データ操作の多い、データによる画面更新の多い Web app だったら、Angular.js を使ったほうが遥かに開発効率があがります。特にbootstrap と一緒に使うとき。

 私は以前他の js library を使ったことも結構ありますが、 AngularJS は開発思想から違うので、Think in AngularJS が必要ですね。また後日で。

 それでは。