AngularJSのソースコードを読んでみた(その1: 起動シーケンス編)
そもそも
AngularJSを使いつつ、”これってどんな感じで動いているんだろう・・・”というのが気になったので、AngularJSのソースコードをざっと眺めてみました。が、僕は特にJavascriptが得意なわけではない上にそこまでしっかり時間をかけられていないので、間違いが含まれている可能性があります(あらかじめ言い訳・・・)
今回の目標
まずはライブラリ(angular.js)がざっくり、どんなシーケンスで動き始めるかを調べてみました。対象としたのは、この時点での最新の1.4.2です。
Entry point
まずは、angular.jsの一番下あたり、行数でいえば28356行目のbindJQuery()から始まります。このメソッド内でJQueryを使う設定をしています。その後、jquery準備完了のコールバックが返ってきたら、angularの初期化が始まります。コードはこんな感じ。
jqLite(document).ready(function() { angularInit(document, bootstrap); });
このangularInitのメソッドでは、ng-appの設定をしています。どうやら、複数のng-appがある場合は、一番最初に見つかったng-ppをroot elementとするようです。
また、bindJQueryからコールバックが返ってくるまでの間に、publishExternalAPI()メソッドが呼ばれています。このメソッドの中で、AngularJS内で共通で使われるメソッドの定義(isFunctionとかisObjectとか)、各Directiveの定義(ngInitDirectiveなど、ng-xxxをはじめ、HTMLのa(アンカー)やformなども含む)、各Providerの定義($logや$httpなども、実はすべてそれ用のProviderがあって、それぞれ$LogProvider、$HttpProviderと呼ぶようです)などを行っています。行数で言うと、2361行目以降です。
コードを抜粋すると、こんな感じ。
function publishExternalAPI(angular) { extend(angular, { //メソッドの定義 'bootstrap': bootstrap, 'copy': copy, . . }); //Directiveの定義 $provide.provider('$compile', $CompileProvider). directive({ a: htmlAnchorDirective, input: inputDirective, . . }). //Providerの定義 $provide.provider({ $anchorScroll: $AnchorScrollProvider, $animate: $AnimateProvider, . . }); } ]); }
それぞれのメソッド、Directive, Providerの定義は、このJavascriptファイルの各地に点在しています。例えば上で出てきたhtmlAnchorDirectiveであれば19390行目あたりにあります。
また、このメソッドからはsetupModuleLoader()というメソッドも呼ばれているのですが、この中でProvider, Factory, Serviceがいつ設定されるか?を決めています。runとconfigのフェーズで設定できる/できないの違いって、ここから生まれているようです。
その他、Angular的なもの
AngularJSって、何か問題が起こったときに結構親切にエラーを吐いてくれると思うのですが、その実際の処理言は、minErr()というメソッドの中でいろいろやっているようです。これはangular.jsの一番上、38行目あたりにあります。
"DirectiveはCamel caseで"という謎の縛り。これはdirectiveNormalize()というメソッドがあり(8769行目あたり)、ここから呼ばれるcamelCaseというメソッド内で行われています。
ということで
もう少し、時間を見つけていろいろと読み進めてみたいと思います。$applyや$digestのあたりも、読んでると(イマイチ理解しきれていないにしても)”なるほどねー。”というところもあり、なかなか面白いものです。