AngularJs Service,Factory,Providerなどなど

最近angularjsを使っていて、少し理解がすすんだ(理解していない部分が明確になってきた)のでちょっとメモ。

Angular面白い&便利だけど、難しい…。主にGoogle先生とMastering Web Application Development With Angularjsを読みながら最低限の知識だけの状態。。

Service,Value,Factory,Provider ってなんぞ?

先ず、サービスとは…

Angularサービスはシングルトンオブジェクト、またはWebアプリケーション共通の特定のタスクを実行する関数です。 Angularは、サーバにリクエストを送るブラウザのXMLHttpRequestオブジェクトにアクセスする$httpサービスのような、 いくつかの組み込みサービスを持ちます。 他のコアなAngular変数と識別子と同様に、組み込みのサービスは常に$から始まります。(前述した$httpのように) また、独自のカスタムサービスを作ることも可能です。

とのこと。 (http://js.studio-kingdom.com/angularjs/guide/understanding_services)

このサービスをDIに登録する方法が複数あり、大分とまどいました。

value

  • 単純なObjectを保持させる為に使う
  • コンストラクタ(function)も登録可能だが、DIを使えない。

APIのエンドポイントなどを保持するなら、constantを使った方がconfigurationフェーズで参照できるなど利点が大きいと思われる。

service

  • 既に存在するangular外に存在するコンストラクタ(function)をAngularのDI機構に登録する時に使う。
  • DIを使えるが、固有の名前空間を持つ事ができない(やってできない事はないが煩雑になる)

↓こんな事をするサンプルを見かけるが、こういった実装はfactoryを使うと簡略化できるのでfactoryを使うべき。

module.service('myService', function($http){
    var SOME_API = 'http://api/hogehoge';

    return function(){
        this.something = function(){
            return $http.get(SOME_API);
        }
    }
});

Factory

  • 新しくserviceとしてコンストラクタを作成する時に使う。
  • プライベートな名前空間を持てるので、thisを使わずしてプライベートなメソッドの実装が可能。
module.factory('myService', function($http, SOME_API){
    // private method
    function callAPI(){
        return $http.get(SOME_API);
    }

    return {
        // public API
        something: function(){
            return callAPI();
        }
    }
});
  • デフォルト値が無いような、必ず設定すべき設定項目などはconstantで設定すると良い
module.constant(SOME_API, 'http://example.com/api');

Provider

  • ユースケースはFactoryとほぼ同じ。
  • サービス固有の設定を行えるような実装をする場合、Providerを使う事でconfigurationフェーズで外部から設定を行えるようになる。
  • Value, Service, Factory は全て内部的にproviderを呼び出している。
module.provider('myProvider', function(){
    var config = {
        SOME_API: 'http://api.example.com'
    };

    return {
        setAPI: function(endpoint){
            config.SOME_API = endpoint;
        },
        
        $get: function($http){
            return {
                something: function(){
                    return $http.get(config.SOME_API);
                }
            }
        }
    }

})

上記サービスをconfigurationフェーズで呼び出す事で、config.SOME_APIの値を変更する事が可能になる。

module.config(function(myProviderProvider){
    myProviderProvider.setAPI('http://api/fugafuga');
});

雑なまとめ

  • 基本的には、factoryメソッドを使ってサービスを登録する。
  • サービス固有の設定項目を設ける場合はproviderを使って外部から設定を行えるようにすると良い。

実際にAngularでアプリケーションを実装してみて、serviceを使うタイミングは殆ど無かった。

Module

  • モジュール間でServiceのDIは可能
  • アプリケーションで読み込んだ全モジュールの中で同じ名前を持つサービスは1つだけ
    • =オーバーライドする事が可能 (曖昧な命名をすると事故が起こる)
  • 結局1つにまとめられるのにモジュールとして分けるのはテスタビリティ向上の為

Moduleについては本で読んで「ふーん」程度に思いつつ実開発時はモジュールを分けずにいました。結果、テストが他サービスに影響を受けどんどん複雑になってしまい、このモジュール分けの重要性を思い知った次第です。。

デバッグ

DevToolなど外からサービスのインスタンスを取得

デバッグや、簡単なスニペットを試している時など、サービスをDevToolのコンソールから実行してステップ実行などしたい場合、どうすれば良いのか…といった事。

$http = angular.element(document.body).injector().get('$http');

とすると$httpサービスのインスタンスを取得できる。

インスタンスさえ取得出来てしまえば、$http.get('http://www.example.com/')などサービスのメソッドを呼び出せる。

Chromeでエラーメッセージが出ない時

基本Chromeで開発しているのですが、なぜかエラーがコンソールに表示されない事が何度かありました。
試しにFirefox&Firebugで実行したところメッセージが表示された。

今後

まだMastering Web Application Development読み終えてないので、しっかり読んで理解を進めようと思います。 (基本の「キ」くらいしかわっていないまま実装を進めてしまい、カオスを生み出してしまったので反省…。)

Angular以外には、Backboneくらいしか触った事が無いけど、Angular楽しいのでとりあえずAngularをマスターしたいと思う。

SHOTA

I'm WEB developer

Tokyo, Japan http://senta.me/