AngularJS:サービスvsプロバイダーvsファクトリー


3319

違いは何ですかServiceProviderFactoryAngularJSには?


244
Angularの用語はすべて、初心者には威圧的でした。プログラマーがAngulardemisx.github.io/angularjs/2014/09/14/…を学びながら理解しやすいこのチートシートから始めました。これがあなたのチームにも役立つことを願っています。
demisx 2014

7
:私の意見では、違いを理解する最良の方法は、角自身のドキュメントを使用しているdocs.angularjs.org/guide/providers、それは非常によく説明されているが、あなたはそれを理解するために特異な例を使用しています。
Rafael Merlin

3
@ブレーズありがとうございます!私の経験からのユースケースの99%はを介して正常に処理できるため、投稿のコメントに従って意図的に省略しましたservice.factory。この主題をさらに複雑にしたくなかった。
demisx 2016年

3
この議論にも非常に便利なI見つけるstackoverflow.com/questions/18939709/...
アナンド・グプタ

3
とがどのように機能するかについてservicesいくつかの良い答えがfactoriesありprovidersます。
Mistalis

回答:


2866

AngularJSメーリングリストから、サービス、ファクトリ、プロバイダー、およびそれらのインジェクションの使用法を説明する素晴らしいスレッドを受け取りまし。答えをまとめる:

サービス

構文:module.service( 'serviceName', function );
結果:serviceNameを注入可能な引数として宣言すると、関数のインスタンスが提供されます。つまり new FunctionYouPassedToService()

工場

構文:module.factory( 'factoryName', function );
結果:factoryNameを注入可能な引数として宣言すると、module.factoryに渡された関数参照を呼び出すことによって返される値が提供されます

プロバイダー

構文:module.provider( 'providerName', function );
結果:providerNameを注入可能な引数として宣言すると、が提供され (new ProviderFunction()).$get()ます。コンストラクター関数は、$ getメソッドが呼び出される前にインスタンス化されますProviderFunction。これは、module.providerに渡される関数参照です。

プロバイダーには、モジュール構成フェーズ中に構成できるという利点があります。

提供されているコードについては、こちらをご覧ください。

Miskoによるさらに詳しい説明は次のとおりです。

provide.value('a', 123);

function Controller(a) {
  expect(a).toEqual(123);
}

この場合、インジェクターは値をそのまま返します。しかし、値を計算したい場合はどうでしょうか?次に、工場を使用します

provide.factory('b', function(a) {
  return a*2;
});

function Controller(b) {
  expect(b).toEqual(246);
}

そのfactoryため、値を作成する機能があります。ファクトリ関数が他の依存関係を要求できることに注意してください。

しかし、もっとオブジェクト指向になり、Greeterと呼ばれるクラスが必要な場合はどうでしょうか。

function Greeter(a) {
  this.greet = function() {
    return 'Hello ' + a;
  }
}

次に、インスタンス化するには、次のように記述する必要があります

provide.factory('greeter', function(a) {
  return new Greeter(a);
});

次に、このようにコントローラで「挨拶」を求めることができます

function Controller(greeter) {
  expect(greeter instanceof Greeter).toBe(true);
  expect(greeter.greet()).toEqual('Hello 123');
}

しかし、それは言い過ぎです。これを書く短い方法はprovider.service('greeter', Greeter);

しかしGreeter、インジェクションの前にクラスを構成したい場合はどうでしょうか?次に、

provide.provider('greeter2', function() {
  var salutation = 'Hello';
  this.setSalutation = function(s) {
    salutation = s;
  }

  function Greeter(a) {
    this.greet = function() {
      return salutation + ' ' + a;
    }
  }

  this.$get = function(a) {
    return new Greeter(a);
  };
});

次に、これを行うことができます:

angular.module('abc', []).config(function(greeter2Provider) {
  greeter2Provider.setSalutation('Halo');
});

function Controller(greeter2) {
  expect(greeter2.greet()).toEqual('Halo 123');
}

注意点として、servicefactory、およびvalueすべてのプロバイダから派生しています。

provider.service = function(name, Class) {
  provider.provide(name, function() {
    this.$get = function($injector) {
      return $injector.instantiate(Class);
    };
  });
}

provider.factory = function(name, factory) {
  provider.provide(name, function() {
    this.$get = function($injector) {
      return $injector.invoke(factory);
    };
  });
}

provider.value = function(name, value) {
  provider.factory(name, function() {
    return value;
  });
};

58
サービスとファクトリの違いについて説明しているstackoverflow.com/a/13763886/215945もご覧ください。
Mark Rajcok 2013年

3
編集611では、角度定数と値の使用法を追加しました。すでに示されている他の違いを示すため。jsbin.com/ohamub/611/edit
Nick

17
関数のインスタンスを作成することによってサービスが呼び出されますが。実際には、インジェクターごとに1回だけ作成されるため、シングルトンのようになります。docs.angularjs.org/guide/dev_guide.services.creating_services
angelokh

33
この例は、明確で実用的な例を使用しているとすれば、信じられないかもしれません。物事のポイントtoEqualgreeter.Greetは何かを理解しようとして迷う。もう少し現実的で親しみやすいものを使ってみませんか?
カイル・ペネル2014

5
関数expect()を使用することは、何かを説明するには不適切な選択です。次回は実世界のコードを使用してください。
Craig

812

JS Fiddleデモ

"Hello World"の例factory/ service/ / provider

var myApp = angular.module('myApp', []);

//service style, probably the simplest one
myApp.service('helloWorldFromService', function() {
    this.sayHello = function() {
        return "Hello, World!";
    };
});

//factory style, more involved but more sophisticated
myApp.factory('helloWorldFromFactory', function() {
    return {
        sayHello: function() {
            return "Hello, World!";
        }
    };
});
    
//provider style, full blown, configurable version     
myApp.provider('helloWorld', function() {

    this.name = 'Default';

    this.$get = function() {
        var name = this.name;
        return {
            sayHello: function() {
                return "Hello, " + name + "!";
            }
        }
    };

    this.setName = function(name) {
        this.name = name;
    };
});

//hey, we can configure a provider!            
myApp.config(function(helloWorldProvider){
    helloWorldProvider.setName('World');
});
        

function MyCtrl($scope, helloWorld, helloWorldFromFactory, helloWorldFromService) {
    
    $scope.hellos = [
        helloWorld.sayHello(),
        helloWorldFromFactory.sayHello(),
        helloWorldFromService.sayHello()];
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="myApp">
<div ng-controller="MyCtrl">
    {{hellos}}
</div>
</body>


2
関数のthisコンテキストを変更しません$getか?-その関数でインスタンス化されたプロバイダーを参照しなくなりました。
Nate-Wilkins

12
@Nate:this実際に呼び出されるのはnew Provider()。$ get()であるため、コンテキストは変更されません。ここProviderで、関数はに渡されapp.providerます。つまり、それは$get()構築されたのメソッドとして呼び出されているProviderので、例が示すようthisに参照さProviderれます。
ブランドン

1
@Brandon Ohhわかりました。一見混乱している-説明してくれてありがとう!
Nate-Wilkins

3
Unknown provider: helloWorldProvider <- helloWorldこれをローカルで実行するとなぜ取得されるのですか?コメントアウト、他の2つの例と同じエラー。非表示のプロバイダー構成はありますか?(Angular 1.0.8)-見つかりました:stackoverflow.com/questions/12339272/…–
Antoine

4
@Antoineが「不明な提供:helloWorldProvider」エラーを受け取るのは、.configコードでは「helloWorldProvider」を使用するためですが、myApp.provider( 'helloWorld'、function())でプロバイダーを定義すると、 'こんにちは世界'?言い換えると、構成コードで、angularはhelloWorldプロバイダーを参照していることをどのようにして知るのですか?ありがとう
jmtoung 2014年

645

TL; DR

1)あなたが使用している工場を、あなたがオブジェクトを作成し、その同じオブジェクトを返し、それにプロパティを追加します。このファクトリーをコントローラーに渡すと、オブジェクトのこれらのプロパティは、ファクトリーを通じてそのコントローラーで使用できるようになります。

app.controller(‘myFactoryCtrl’, function($scope, myFactory){
  $scope.artist = myFactory.getArtist();
});

app.factory(‘myFactory’, function(){
  var _artist = Shakira’;
  var service = {};

  service.getArtist = function(){
    return _artist;
  }

  return service;
});


2)Serviceを使用している場合、AngularJSは「new」キーワードを使用して、サービスをバックグラウンドでインスタンス化します。そのため、プロパティを「this」に追加すると、サービスは「this」を返します。サービスをコントローラーに渡すと、「this」のこれらのプロパティは、サービスを通じてそのコントローラーで使用できるようになります。

app.controller(‘myServiceCtrl’, function($scope, myService){
  $scope.artist = myService.getArtist();
});

app.service(‘myService’, function(){
  var _artist = Nelly’;
  this.getArtist = function(){
    return _artist;
  }
});



3) プロバイダーは、.config()関数に渡すことができる唯一のサービスです。サービスオブジェクトを使用可能にする前に、サービスオブジェクトのモジュール全体の構成を提供する場合は、プロバイダーを使用します。

app.controller(‘myProvider’, function($scope, myProvider){
  $scope.artist = myProvider.getArtist();
  $scope.data.thingFromConfig = myProvider.thingOnConfig;
});

app.provider(‘myProvider’, function(){
 //Only the next two lines are available in the app.config()
 this._artist = ‘’;
 this.thingFromConfig = ‘’;
  this.$get = function(){
    var that = this;
    return {
      getArtist: function(){
        return that._artist;
      },
      thingOnConfig: that.thingFromConfig
    }
  }
});

app.config(function(myProviderProvider){
  myProviderProvider.thingFromConfig = This was set in config’;
});



非TL; DR

1)ファクトリファクトリ
は、サービスを作成および構成する最も一般的な方法です。TL; DRが言った以上のことは本当にありません。オブジェクトを作成し、それにプロパティを追加して、同じオブジェクトを返すだけです。次に、ファクトリをコントローラーに渡すと、オブジェクトのこれらのプロパティは、ファクトリを介してそのコントローラーで使用できるようになります。より広範な例を以下に示します。

app.factory(‘myFactory’, function(){
  var service = {};
  return service;
});

これで、「myFactory」をコントローラーに渡すと、「service」にアタッチしたすべてのプロパティを使用できるようになります。

次に、いくつかの「プライベート」変数をコールバック関数に追加しましょう。これらはコントローラーから直接アクセスできませんが、必要に応じてこれらの「プライベート」変数を変更できるように、最終的に「サービス」にいくつかのゲッター/セッターメソッドを設定します。

app.factory(‘myFactory’, function($http, $q){
  var service = {};
  var baseUrl = https://itunes.apple.com/search?term=’;
  var _artist = ‘’;
  var _finalUrl = ‘’;

  var makeUrl = function(){
   _artist = _artist.split(‘ ‘).join(‘+’);
    _finalUrl = baseUrl + _artist + ‘&callback=JSON_CALLBACK’;
    return _finalUrl
  }

  return service;
});

ここで、これらの変数/関数を「サービス」にアタッチしていないことに気づくでしょう。後で使用または変更するために、単に作成しています。

  • baseUrlは、iTunes APIが必要とするベースURLです
  • _artistは、検索するアーティストです
  • _finalUrlは、iTunesを呼び出す最終的な完全に構築されたURLです。
  • makeUrlは、iTunesと相性の良いURLを作成して返す関数です。

ヘルパー/プライベート変数と関数が用意できたので、「サービス」オブジェクトにいくつかのプロパティを追加しましょう。「サービス」に設定したものは、「myFactory」を渡すどのコントローラー内でも直接使用できます。

アーティストを返すか設定するだけのsetArtistメソッドとgetArtistメソッドを作成します。また、作成したURLでiTunes APIを呼び出すメソッドを作成します。このメソッドは、iTunes APIからデータが返されると満たされるpromiseを返します。AngularJSでpromiseを使用した経験があまりない場合は、promiseについて詳しく説明することを強くお勧めします。

以下のsetArtistはアーティストを受け入れ、アーティストを設定できます。getArtistはアーティストを返します。callItunesは、最初にmakeUrl()を呼び出して、$ httpリクエストで使用するURLを作成します。次に、promiseオブジェクトを設定し、最終的なURLを使用して$ httpリクエストを作成します。$ httpはpromiseを返すため、リクエストの後に.successまたは.errorを呼び出すことができます。その後、iTunesデータで約束を解決するか、「エラーが発生しました」というメッセージで拒否します。

app.factory('myFactory', function($http, $q){
  var service = {};
  var baseUrl = 'https://itunes.apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  var makeUrl = function(){
    _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
    return _finalUrl;
  }

  service.setArtist = function(artist){
    _artist = artist;
  }

  service.getArtist = function(){
    return _artist;
  }

  service.callItunes = function(){
    makeUrl();
    var deferred = $q.defer();
    $http({
      method: 'JSONP',
      url: _finalUrl
    }).success(function(data){
      deferred.resolve(data);
    }).error(function(){
      deferred.reject('There was an error')
    })
    return deferred.promise;
  }

  return service;
});

これで工場が完成しました。これで 'myFactory'を任意のコントローラーに挿入できるようになり、サービスオブジェクト(setArtist、getArtist、callItunes)にアタッチしたメソッドを呼び出すことができるようになります。

app.controller('myFactoryCtrl', function($scope, myFactory){
  $scope.data = {};
  $scope.updateArtist = function(){
    myFactory.setArtist($scope.data.artist);
  };

  $scope.submitArtist = function(){
    myFactory.callItunes()
      .then(function(data){
        $scope.data.artistData = data;
      }, function(data){
        alert(data);
      })
  }
});

上記のコントローラーでは、「myFactory」サービスに注入しています。次に、「myFactory」からのデータを使用して$ scopeオブジェクトにプロパティを設定します。上記の唯一のトリッキーなコードは、これまでに約束を扱ったことがない場合です。callItunesがpromiseを返すため、.then()メソッドを使用して、iTunesデータでpromiseが満たされた場合にのみ$ scope.data.artistDataを設定できます。コントローラーが非常に「薄い」ことに気づくでしょう(これは優れたコーディング慣行です)。ロジックと永続データはすべて、コントローラーではなくサービスにあります。

2)サービス
おそらく、サービスの作成を処理する際に知っておくべき最大のことは、「新しい」キーワードでインスタンス化されるということです。JavaScriptの達人にとって、これはコードの性質に大きなヒントを与えるはずです。JavaScriptのバックグラウンドが限られている方や、「新しい」キーワードの実際の動作に慣れていない方のために、最終的にサービスの性質を理解するのに役立つJavaScriptの基礎を復習しましょう。

「new」キーワードを使用して関数を呼び出したときに発生する変更を実際に確認するには、関数を作成して「new」キーワードを使用して呼び出します。次に、「new」キーワードを検出したときにインタープリターが何を行うかを見てみましょう。最終結果はどちらも同じになります。

まず、コンストラクタを作成しましょう。

var Person = function(name, age){
  this.name = name;
  this.age = age;
}

これは、典型的なJavaScriptコンストラクター関数です。これで、「new」キーワードを使用してPerson関数を呼び出すたびに、「this」が新しく作成されたオブジェクトにバインドされます。

次に、Personのプロトタイプにメソッドを追加して、Personの「クラス」のすべてのインスタンスで使用できるようにします。

Person.prototype.sayName = function(){
  alert(‘My name is  + this.name);
}

ここで、sayName関数をプロトタイプに配置したので、PersonのすべてのインスタンスはsayName関数を呼び出して、そのインスタンスの名前を警告することができます。

Personコンストラクター関数とsayName関数がそのプロトタイプにあるので、実際にPersonのインスタンスを作成してから、sayName関数を呼び出します。

var tyler = new Person(‘Tyler’, 23);
tyler.sayName(); //alerts ‘My name is Tyler’

したがって、Personコンストラクターを作成し、そのプロトタイプに関数を追加し、Personインスタンスを作成し、そのプロトタイプで関数を呼び出すためのコードはすべて、次のようになります。

var Person = function(name, age){
  this.name = name;
  this.age = age;
}
Person.prototype.sayName = function(){
  alert(‘My name is  + this.name);
}
var tyler = new Person(‘Tyler’, 23);
tyler.sayName(); //alerts ‘My name is Tyler’

次に、JavaScriptで「new」キーワードを使用したときに実際に何が起こっているかを見てみましょう。最初に気づくべきことは、この例で「new」を使用した後、まるでオブジェクトであるかのように、「tyler」でメソッド(sayName)を呼び出すことができるということです。したがって、最初に、Personコンストラクターがオブジェクトを返していることがわかります。コードでそれを確認できるかどうかは関係ありません。次に、sayName関数は直接Personインスタンスではなくプロトタイプにあるため、Person関数が返すオブジェクトは、ルックアップが失敗したときにそのプロトタイプに委任されている必要があります。より簡単に言えば、tyler.sayName()を呼び出すと、インタープリターは「OK、先ほど作成した 'tyler'オブジェクトを見て、sayName関数を見つけて呼び出します。ちょっと待ってください、ここには表示されません。表示されるのは名前と年齢だけです。プロトタイプを確認させてください。うん、それはプロトタイプにあるように見えます。私はそれを呼ばせてください。」

以下は、「new」キーワードが実際にJavaScriptで何をしているのかを考える方法のコードです。基本的には、上記の段落のコード例です。「インタープリタービュー」、つまりインタープリターがコードをノート内に表示する方法を示しました。

var Person = function(name, age){
  //The below line creates an object(obj) that will delegate to the person’s prototype on failed lookups.
  //var obj = Object.create(Person.prototype);

  //The line directly below this sets ‘this’ to the newly created object
  //this = obj;

  this.name = name;
  this.age = age;

  //return this;
}

これで、JavaScriptで「新しい」キーワードが実際に何を行うかについての知識が得られたので、AngularJSでサービスを作成する方が理解しやすいはずです。

サービスを作成するときに理解する最大のことは、サービスが「新しい」キーワードでインスタンス化されることを知ることです。この知識と上記の例を組み合わせると、プロパティとメソッドを「this」に直接アタッチし、サービス自体から返されることを認識できるはずです。これを実際に見てみましょう。

最初にFactoryの例で行ったのとは異なり、オブジェクトを作成してからそのオブジェクトを返す必要はありません。これまでに何度も言及したように、「new」キーワードを使用してインタープリターがそのオブジェクトを作成し、デリゲートするようにしているためです。これはプロトタイプであり、作業を行わなくても返却できます。

最初に、「プライベート」ヘルパー関数を作成しましょう。私たちの工場でもまったく同じことをしたので、これは非常に見覚えがあるはずです。ここでは各行が何をするかについては説明しません。工場の例でそれを行ったからです。混乱している場合は、工場の例をもう一度読んでください。

app.service('myService', function($http, $q){
  var baseUrl = 'https://itunes.apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  var makeUrl = function(){
    _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
    return _finalUrl;
  }
});

ここで、コントローラーで使用できるすべてのメソッドを「this」にアタッチします。

app.service('myService', function($http, $q){
  var baseUrl = 'https://itunes.apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  var makeUrl = function(){
    _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
    return _finalUrl;
  }

  this.setArtist = function(artist){
    _artist = artist;
  }

  this.getArtist = function(){
    return _artist;
  }

  this.callItunes = function(){
    makeUrl();
    var deferred = $q.defer();
    $http({
      method: 'JSONP',
      url: _finalUrl
    }).success(function(data){
      deferred.resolve(data);
    }).error(function(){
      deferred.reject('There was an error')
    })
    return deferred.promise;
  }

});

これで、ファクトリと同様に、setServiceist、getArtist、およびcallItunesは、myServiceを渡すどのコントローラーでも使用できるようになります。これがmyServiceコントローラーです(これは、出荷時のコントローラーとほぼ同じです)。

app.controller('myServiceCtrl', function($scope, myService){
  $scope.data = {};
  $scope.updateArtist = function(){
    myService.setArtist($scope.data.artist);
  };

  $scope.submitArtist = function(){
    myService.callItunes()
      .then(function(data){
        $scope.data.artistData = data;
      }, function(data){
        alert(data);
      })
  }
});

前に述べたように、「新しい」機能が本当に理解できたら、サービスはAngularJSのファクトリーとほとんど同じです。

3)プロバイダー

プロバイダーについて覚えておくべき最大のことは、プロバイダーがアプリケーションのapp.config部分に渡すことができる唯一のサービスであることです。これは、サービスオブジェクトの一部をアプリケーションのほかの場所で使用できるようにする前に変更する必要がある場合に非常に重要です。サービス/工場と非常に似ていますが、これから説明するいくつかの違いがあります。

まず、サービスとファクトリーで行ったのと同じ方法でプロバイダーをセットアップします。以下の変数は、「プライベート」およびヘルパー関数です。

app.provider('myProvider', function(){
   var baseUrl = 'https://itunes.apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  //Going to set this property on the config function below.
  this.thingFromConfig = ‘’;

  var makeUrl = function(){
    _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
    return _finalUrl;
  }
}

*上記のコードのいずれかの部分が混乱を招く場合は、ファクトリーセクションをチェックして、すべての機能について詳しく説明します。

プロバイダーは3つのセクションがあると考えることができます。最初のセクションは、後で変更/設定される「プライベート」変数/関数です(上記を参照)。2番目のセクションは、app.config関数で使用できる変数/関数です。したがって、他の場所で使用できるようになる前に変更することができます(これも上記に示されています)。これらの変数は「this」キーワードに付加する必要があることに注意することが重要です。この例では、app.configで変更できるのは「thingFromConfig」だけです。3番目のセクション(下に表示)は、「myProvider」サービスを特定のコントローラーに渡したときにコントローラーで使用できるすべての変数/関数です。

プロバイダーを使用してサービスを作成する場合、コントローラーで使用できるのは、$ get()関数から返されるプロパティ/メソッドのみです。以下のコードは$ getを 'this'に配置します(これは最終的にその関数から返されることがわかっています)。これで、$ get関数はコントローラーで使用できるようにするすべてのメソッド/プロパティを返します。これがコード例です。

this.$get = function($http, $q){
    return {
      callItunes: function(){
        makeUrl();
        var deferred = $q.defer();
        $http({
          method: 'JSONP',
          url: _finalUrl
        }).success(function(data){
          deferred.resolve(data);
        }).error(function(){
          deferred.reject('There was an error')
        })
        return deferred.promise;
      },
      setArtist: function(artist){
        _artist = artist;
      },
      getArtist: function(){
        return _artist;
      },
      thingOnConfig: this.thingFromConfig
    }
  }

完全なプロバイダーコードは次のようになります。

app.provider('myProvider', function(){
  var baseUrl = 'https://itunes.apple.com/search?term=';
  var _artist = '';
  var _finalUrl = '';

  //Going to set this property on the config function below
  this.thingFromConfig = '';

  var makeUrl = function(){
    _artist = _artist.split(' ').join('+');
    _finalUrl = baseUrl + _artist + '&callback=JSON_CALLBACK'
    return _finalUrl;
  }

  this.$get = function($http, $q){
    return {
      callItunes: function(){
        makeUrl();
        var deferred = $q.defer();
        $http({
          method: 'JSONP',
          url: _finalUrl
        }).success(function(data){
          deferred.resolve(data);
        }).error(function(){
          deferred.reject('There was an error')
        })
        return deferred.promise;
      },
      setArtist: function(artist){
        _artist = artist;
      },
      getArtist: function(){
        return _artist;
      },
      thingOnConfig: this.thingFromConfig
    }
  }
});

これで、ファクトリとServiceの場合と同様に、setArtist、getArtist、callItunesは、myProviderを渡すどのコントローラーでも使用できます。これがmyProviderコントローラーです(これは、ファクトリー/サービスコントローラーとほぼ同じです)。

app.controller('myProviderCtrl', function($scope, myProvider){
  $scope.data = {};
  $scope.updateArtist = function(){
    myProvider.setArtist($scope.data.artist);
  };

  $scope.submitArtist = function(){
    myProvider.callItunes()
      .then(function(data){
        $scope.data.artistData = data;
      }, function(data){
        alert(data);
      })
  }

  $scope.data.thingFromConfig = myProvider.thingOnConfig;
});

前述のように、プロバイダーを使用してサービスを作成するポイントは、最終的なオブジェクトがアプリケーションの残りの部分に渡される前に、app.config関数を介していくつかの変数を変更できるようにすることです。その例を見てみましょう。

app.config(function(myProviderProvider){
  //Providers are the only service you can pass into app.config
  myProviderProvider.thingFromConfig = 'This sentence was set in app.config. Providers are the only service that can be passed into config. Check out the code to see how it works';
});

これで、プロバイダーの「thingFromConfig」が空の文字列としてどのように表示されるかを確認できますが、それがDOMに表示されると、「この文は設定されました...」になります。


11
この優れた記事に欠けている唯一の部分は、ファクトリーよりもサービスを使用することの相対的な利点です。これは、Liorが承認した回答で明確に説明されています
無限

2
FWIW(多分あまりないが)、ここでは角度の問題を取るブロガーであり、providerProvider好きではない codeofrob.com/entries/you-have-ruined-javascript.html
barlop

3
「JavaScriptの達人」のパンチラインは陰険でした。:DIは、この答えは非常にクリアになると思います。見事に書かれています。
amarmishra 2017年

4
TLDRにはTLDRが必要です。
JensB 2017年

3
@JensB tl; dr-Reactを学びます。
タイラーマクギニス2017年

512

すべてのサービスはシングルトンです。アプリごとに1回インスタンス化されます。彼らはすることができ、あらゆるタイプのそれは原始的な、オブジェクトリテラル、関数、またはカスタムタイプのさえインスタンスであるかどうか、。

valuefactoryserviceconstant、およびprovider方法は、すべてのプロバイダです。彼らはインジェクターにサービスをインスタンス化する方法を教えます。

最も冗長で最も包括的なものは、プロバイダーレシピです。残りの4つのレシピタイプ-値、工場、サービスおよび定数は- プロバイダレシピの上部にだけ糖衣構文です

  • 値のレシピは、あなたがサービス自身をインスタンス化し、提供し、最も単純なケースであり、インスタンス化された値をインジェクタに。
  • 工場のレシピはインジェクタにそれがサービスをインスタンス化する必要があるときにそれが呼び出すファクトリ関数を提供します。呼び出されると、ファクトリ関数はサービスインスタンスを作成して返します。サービスの依存関係は、関数の引数として挿入されます。したがって、このレシピを使用すると、次の能力が追加されます。
    • 他のサービスを使用する機能(依存関係がある)
    • サービスの初期化
    • 遅延/遅延初期化
  • サービスのレシピは、工場出荷時のレシピとほとんど同じであるが、ここではインジェクタが呼び出すコンストラクタを代わりにファクトリ関数のnew演算子と。
  • プロバイダレシピは、通常、やり過ぎ。ファクトリの作成を構成できるようにすることで、間接層がさらに1つ追加されます。

    アプリケーションの起動前に行う必要があるアプリケーション全体の構成用のAPIを公開する場合にのみ、プロバイダーレシピを使用する必要があります。これは通常、動作がアプリケーション間でわずかに異なる必要がある可能性がある再利用可能なサービスでのみ興味深いものです。

  • 定数レシピはちょうどそれはあなたが利用可能なサービスを定義することを可能にする以外バリューレシピのようなものです設定フェーズを。Valueレシピを使用して作成されたサービスよりも早く。値とは異なり、それらを使用して装飾することはできませんdecorator
プロバイダーのドキュメントを 参照してください。


2
では、サービスと工場は基本的に同じですか?他のいずれかを使用すると、代替構文以外に何も提供されませんか?
マット

2
@マット、はい、サービスは、サービスとして公開したい独自の関数が既にある場合、簡潔な方法です。ドキュメントから:myApp.factory( 'unicornLauncher'、["apiToken"、function(apiToken){return new UnicornLauncher(apiToken);}]); vs:myApp.service( 'unicornLauncher'、["apiToken"、UnicornLauncher]);
janek

5
@joshperry初心者として、しばらくの間、サービスとファクトリーの違いをググってきました。これはこれまでで最高の答えだと思います。私は、サービスをサービスクラス(エンコーダー/デコーダークラスなど)として理解します。これには、いくつかのプライベートプロパティがある場合があります。そして、factoryはステートレスヘルパーメソッドのセットを提供します。
stanleyxu2005 2015年

3
上記の他の回答のYaaの例では、これらのレシピがインスタンス化されるときに挿入される、コアとなるb / wサービスとプロバイダーの違いを非常に明確に説明できていません。
Ashish Singh

223

AngularJSファクトリ、サービス、プロバイダーについて

これらはすべて、再利用可能なシングルトンオブジェクトを共有するために使用されます。アプリ/さまざまなコンポーネント/モジュール間で再利用可能なコードを共有するのに役立ちます。

ドキュメントサービス/ファクトリから

  • 遅延インスタンス化 – Angularは、アプリケーションコンポーネントが依存している場合にのみサービス/ファクトリをインスタンス化します。
  • シングルトン –サービスに依存する各コンポーネントは、サービスファクトリによって生成された単一のインスタンスへの参照を取得します。

工場

ファクトリは、オブジェクトを作成する前にロジックを操作/追加できる関数で、新しく作成されたオブジェクトが返されます。

app.factory('MyFactory', function() {
    var serviceObj = {};
    //creating an object with methods/functions or variables
    serviceObj.myFunction = function() {
        //TO DO:
    };
    //return that object
    return serviceObj;
});

使用法

これは、クラスのような関数の単なるコレクションにすることができます。したがって、コントローラー/ファクトリー/ディレクティブ関数内に注入するときに、別のコントローラーでインスタンス化できます。アプリごとに1回だけインスタンス化されます。

サービス

単にサービスを見ながら、アレイのプロトタイプについて考えます。サービスは、「new」キーワードを使用して新しいオブジェクトをインスタンス化する関数です。thisキーワードを使用して、サービスオブジェクトにプロパティと関数を追加できます。ファクトリとは異なり、何も返しません(メソッド/プロパティを含むオブジェクトを返します)。

app.service('MyService', function() {
    //directly binding events to this context
    this.myServiceFunction = function() {
        //TO DO:
    };
});

使用法

アプリケーション全体で単一のオブジェクトを共有する必要がある場合に使用します。たとえば、認証されたユーザーの詳細、共有可能なメソッド/データ、ユーティリティ関数など。

プロバイダー

プロバイダーは、構成可能なサービスオブジェクトを作成するために使用されます。設定機能からサービス設定を行うことができます。$get()関数を使用して値を返します。$get関数は、角度で実行フェーズで実行されます。

app.provider('configurableService', function() {
    var name = '';
    //this method can be be available at configuration time inside app.config.
    this.setName = function(newName) {
        name = newName;
    };
    this.$get = function() {
        var getName = function() {
             return name;
        };
        return {
            getName: getName //exposed object to where it gets injected.
        };
    };
});

使用法

サービスオブジェクトを使用可能にする前に、モジュールごとの構成を提供する必要がある場合。のような環境に基づいてAPI URLを設定したいとしますdevstageまたはprod

注意

Angularの設定フェーズで利用できるのはプロバイダーのみですが、サービスとファクトリーでは利用できません。

これにより、工場、サービス、プロバイダーに関する理解が深まったことを願っています


1
特定のインターフェイスを持つサービスがあり、2つの異なる実装があり、それぞれをコントローラーに挿入するが、ui-routerを使用して異なる状態に関連付けたい場合はどうすればよいですか?たとえば、ある状態でリモート呼び出しを行いますが、別の状態ではなくローカルストレージに書き込みます。プロバイダーのドキュメントはを使用するonly when you want to expose an API for application-wide configuration that must be made before the application starts. This is usually interesting only for reusable services whose behavior might need to vary slightly between applicationsように言っているので、聞こえませんか?
qix

191

私にとって、啓示は、すべてが同じように動作することに気付いたときに発生しました。何かを一度実行し、取得した値を格納し、依存関係の注入を通じて参照されたときに、同じ格納された値を消去します。

私たちが持っているとしましょう:

app.factory('a', fn);
app.service('b', fn);
app.provider('c', fn);

3つの違いは次のとおりです。

  1. aの格納された値は、実行から取得されますfn
  2. bの保存値はnewing から取得されますfn
  3. cの格納された値は、最初にnewing によってインスタンスを取得し、fn次に$getインスタンスのメソッドを実行することから取得されます。

これは、AngularJS内にキャッシュオブジェクトのようなものがあることを意味します。各インジェクションの値は、最初にインジェクションされたときに一度だけ割り当てられます。

cache.a = fn()
cache.b = new fn()
cache.c = (new fn()).$get()

これがthis、サービスで使用しthis.$get、プロバイダーでを定義する理由です。


2
私もこの答えが一番好きです。それらすべてのポイントは、DIを通じて必要なときにいつでもオブジェクトへのアクセスを提供することです。通常はfactorysで問題ありません。service存在する唯一の理由は、CoffeeScript、TypeScript、ES6などの言語であるため、これらのクラス構文を使用できます。が必要なproviderのは、を使用して、設定が異なる複数のアプリケーションでモジュールを使用する場合のみですapp.config()。サービスが純粋なシングルトンであるか、または何かのインスタンスを作成できるかどうかは、実装に依存します。
Andreas Linnert

137

サービスvsプロバイダーvs工場:

私はそれをシンプルに保つようにしています。基本的なJavaScriptの概念がすべてです。

まず最初に、AngularJSのサービスについて話しましょう!

サービスとは: AngularJSでは、サービスいくつかの便利なメソッドやプロパティを格納できるシングルトンJavaScriptオブジェクトにすぎません。このシングルトンオブジェクトはngApp(Angular app)ベースで作成され、現在のアプリ内のすべてのコントローラー間で共有されます。Angularjsはサービスオブジェクトをインスタンス化するときに、このサービスオブジェクトを一意のサービス名で登録します。したがって、サービスインスタンスが必要になるたびに、Angularはレジストリでこのサービス名を検索し、サービスオブジェクトへの参照を返します。そのため、サービスオブジェクトのメソッドを呼び出したり、プロパティにアクセスしたりできます。コントローラーのスコープオブジェクトにプロパティ、メソッドを配置できるかどうか疑問に思うかもしれません!では、なぜサービスオブジェクトが必要なのでしょうか。答えは次のとおりです。サービスは複数のコントローラースコープ間で共有されます。一部のプロパティ/メソッドをコントローラーのスコープオブジェクトに配置すると、現在のスコープでのみ使用できるようになります。

したがって、3つのコントローラースコープがある場合、コントローラーA、コントローラーB、コントローラーCとすると、すべてが同じサービスインスタンスを共有します。

<div ng-controller='controllerA'>
    <!-- controllerA scope -->
</div>
<div ng-controller='controllerB'>
    <!-- controllerB scope -->
</div>
<div ng-controller='controllerC'>
    <!-- controllerC scope -->
</div>

サービスを作成するには?

AngularJSは、サービスを登録するためのさまざまなメソッドを提供します。ここでは、factory(..)、service(..)、provider(..)の3つのメソッドに集中します。

このリンクをコード参照に使用します

工場機能:

ファクトリ関数は以下のように定義できます。

factory('serviceName',function fnFactory(){ return serviceInstance;})

AngularJSは、serviceNameとJavaScript関数の2つのパラメーターを取る'factory(' serviceName '、fnFactory)'メソッドを提供します。Angularは、以下のような関数fnFactory()を呼び出すことでサービスインスタンスを作成します。

var serviceInstace = fnFactory();

渡された関数はオブジェクトを定義し、そのオブジェクトを返すことができます。AngularJSは、このオブジェクト参照を、最初の引数として渡される変数に格納するだけです。fnFactoryから返されるものはすべてserviceInstanceにバインドされます。オブジェクトを返す代わりに、関数や値などを返すこともできます。返すものは何でも、サービスインスタンスで利用できます。

例:

var app= angular.module('myApp', []);
//creating service using factory method
app.factory('factoryPattern',function(){
  var data={
    'firstName':'Tom',
    'lastName':' Cruise',
    greet: function(){
      console.log('hello!' + this.firstName + this.lastName);
    }
  };

  //Now all the properties and methods of data object will be available in our service object
  return data;
});

サービス機能:

service('serviceName',function fnServiceConstructor(){})

それは別の方法です。サービスを登録できます。唯一の違いは、AngularJSがサービスオブジェクトをインスタンス化する方法です。今回、angularは 'new'キーワードを使用して、以下のようなコンストラクター関数を呼び出します。

var serviceInstance = new fnServiceConstructor();

コンストラクター関数では、サービスオブジェクトにプロパティ/メソッドを追加するために「this」キーワードを使用できます。例:

//Creating a service using the service method
var app= angular.module('myApp', []);
app.service('servicePattern',function(){
  this.firstName ='James';
  this.lastName =' Bond';
  this.greet = function(){
    console.log('My Name is '+ this.firstName + this.lastName);
  };
});

プロバイダー機能:

Provider()関数は、サービスを作成するもう1つの方法です。ユーザーに挨拶メッセージを表示するだけのサービスを作成してみましょう。しかし、ユーザーが独自の挨拶メッセージを設定できるような機能も提供したいと考えています。技術的には、構成可能なサービスを作成したいと考えています。どうすればこれを行うことができますか?アプリがカスタムグリーティングメッセージを渡し、Angularjsがサービスインスタンスを作成するファクトリー/コンストラクター関数で利用できるようにする方法が必要です。このような場合、provider()関数がその役割を果たします。provider()関数を使用して、構成可能なサービスを作成できます。

以下に示すプロバイダー構文を使用して、構成可能サービスを作成できます。

/*step1:define a service */
app.provider('service',function serviceProviderConstructor(){});

/*step2:configure the service */
app.config(function configureService(serviceProvider){});

プロバイダーの構文は内部的にどのように機能しますか?

1.Providerオブジェクトは、プロバイダー関数で定義したコンストラクター関数を使用して作成されます。

var serviceProvider = new serviceProviderConstructor();

2. app.config()で渡した関数が実行されます。これは設定フェーズと呼ばれ、ここでサービスをカスタマイズする機会があります。

configureService(serviceProvider);

3.最後に、serviceProviderの$ getメソッドを呼び出すことにより、サービスインスタンスが作成されます。

serviceInstance = serviceProvider.$get()

構文を使用してサービスを作成するためのサンプルコード:

var app= angular.module('myApp', []);
app.provider('providerPattern',function providerConstructor(){
  //this function works as constructor function for provider
  this.firstName = 'Arnold ';
  this.lastName = ' Schwarzenegger' ;
  this.greetMessage = ' Welcome, This is default Greeting Message' ;
  //adding some method which we can call in app.config() function
  this.setGreetMsg = function(msg){
    if(msg){
      this.greetMessage =  msg ;
    }
  };

  //We can also add a method which can change firstName and lastName
  this.$get = function(){
    var firstName = this.firstName;
    var lastName = this.lastName ;
    var greetMessage = this.greetMessage;
    var data={
       greet: function(){
         console.log('hello, ' + firstName + lastName+'! '+ greetMessage);
       }
    };
    return data ;
  };
});

app.config(
  function(providerPatternProvider){
    providerPatternProvider.setGreetMsg(' How do you do ?');
  }
);

作業デモ

概要:


ファクトリは、サービスインスタンスを返すファクトリ関数を使用します。 serviceInstance = fnFactory();

サービスはコンストラクター関数を使用し、Angularはサービスインスタンスを作成するために 'new'キーワードを使用してこのコンストラクター関数を呼び出します。 serviceInstance = new fnServiceConstructor();

プロバイダーはproviderConstructor関数を定義し、このproviderConstructor関数はファクトリー関数$ getを定義します。Angularは$ get()を呼び出してサービスオブジェクトを作成します。プロバイダーの構文には、インスタンス化される前にサービスオブジェクトを設定できるという利点があります。 serviceInstance = $ get();


87

ここで数人の人々が正しく指摘しているように、ファクトリー、プロバイダー、サービス、さらには価値と定数さえも同じもののバージョンです。より一般的なものproviderをそれらすべてに分解することができます。そのようです:

ここに画像の説明を入力してください

この画像の記事は次のとおりです。

http://www.simplygoodcode.com/2015/11/the-difference-between-service-provider-and-factory-in-angularjs/


63

工場

AngularJSに関数を与えると、AngularJSはファクトリがリクエストされたときに戻り値をキャッシュして注入します。

例:

app.factory('factory', function() {
    var name = '';
    // Return value **is** the object that will be injected
    return {
        name: name;
    }
})

使用法:

app.controller('ctrl', function($scope, factory) {
     $scope.name = factory.name;
});

サービス

AngularJSに関数を与えると、AngularJSはnewを呼び出してインスタンス化します。AngularJSが作成するインスタンスは、サービスが要求されたときにキャッシュされ、挿入されます。以来、新規にサービスをインスタンス化するために使用された、キーワードが、これは有効であり、インスタンスを指します。

例:

app.service('service', function() {
     var name = '';
     this.setName = function(newName) {
         name = newName;
     }
     this.getName = function() {
         return name;
     }
});

使用法:

app.controller('ctrl', function($scope, service) {
   $scope.name = service.getName();
});

プロバイダー

AngularJSに関数を指定すると、AngularJSがその$get関数を呼び出します。これは、$getサービスが要求されたときにキャッシュおよび挿入される関数からの戻り値です。

プロバイダーを使用すると、AngularJSがメソッドを呼び出して注入可能オブジェクトを取得するにプロバイダーを構成できます$get

例:

app.provider('provider', function() {
     var name = '';
     this.setName = function(newName) {
          name = newName;
     }
     this.$get = function() {
         return {
            name: name
         }
     }
})

使用法(コントローラーの注入可能オブジェクトとして)

app.controller('ctrl', function($scope, provider) {
    $scope.name = provider.name;
});

使用法($getインジェクタブルを作成するために前にプロバイダーを構成することが呼び出されます)

app.config(function(providerProvider) {
    providerProvider.setName('John');
});

56

プロバイダーで遊んでいるときに、何か面白いことに気づきました。

注射剤の可視性は、プロバイダーとサービスや工場では異なります。AngularJSを「定数」として宣言した場合(たとえば、myApp.constant('a', 'Robert');)それをサービス、ファクトリー、プロバイダーに注入できます。

ただし、AngularJSの「値」(たとえば、myApp.value('b', {name: 'Jones'});)を宣言した場合、サービスやファクトリに注入できますが、プロバイダー作成関数には注入できません。ただし、$getプロバイダー用に定義した関数に挿入することはできます。これはAngularJSのドキュメントで言及されていますが、見落としがちです。これは、%provideページのvalueメソッドとconstantメソッドのセクションにあります。

http://jsfiddle.net/R2Frv/1/

<div ng-app="MyAppName">
    <div ng-controller="MyCtrl">
        <p>from Service: {{servGreet}}</p>
        <p>from Provider: {{provGreet}}</p>
    </div>
</div>
<script>
    var myApp = angular.module('MyAppName', []);

    myApp.constant('a', 'Robert');
    myApp.value('b', {name: 'Jones'});

    myApp.service('greetService', function(a,b) {
        this.greeter = 'Hi there, ' + a + ' ' + b.name;
    });

    myApp.provider('greetProvider', function(a) {
        this.firstName = a;
        this.$get = function(b) {
            this.lastName = b.name;
            this.fullName = this.firstName + ' ' + this.lastName;
            return this;
        };
    });

    function MyCtrl($scope, greetService, greetProvider) {
        $scope.servGreet = greetService.greeter;
        $scope.provGreet = greetProvider.fullName;
    }
</script>

45

これは初心者にとって非常に混乱する部分であり、簡単な言葉でそれを明確にしようとしました

AngularJSサービス:コントローラーのサービス参照とユーティリティ関数を共有するために使用されます。サービスは本質的にシングルトンであるため、1つのサービスに対して1つのインスタンスのみがブラウザーで作成され、同じ参照がページ全体で使用されます。

サービスでは、このオブジェクトのプロパティとして関数名を作成します。

AngularJS Factory:Factoryの目的もServiceと同じですが、この場合、新しいオブジェクトを作成し、このオブジェクトのプロパティとして関数を追加し、最後にこのオブジェクトを返します。

AngularJSプロバイダー:目的は同じですが、プロバイダーは$ get関数の出力を提供します。

サービス、ファクトリー、プロバイダーの定義と使用については、http://www.dotnetfunda.com/articles/show/3156/difference-between-angularjs-service-factory-and-providerで説明されています。


2
ファクトリーとプロバイダーもシングルトンオブジェクトですか?サービスよりも工場が推奨されているscanrioはありますか?
Sunil Garg

34

私にとって、違いを理解する最良かつ最も簡単な方法は次のとおりです。

var service, factory;
service = factory = function(injection) {}

AngularJSが特定のコンポーネントをインスタンス化する方法(簡略化):

// service
var angularService = new service(injection);

// factory
var angularFactory = factory(injection);

したがって、サービスの場合、AngularJSコンポーネントになるのは、サービス宣言関数によって表されるクラスのオブジェクトインスタンスです。ファクトリーの場合は、ファクトリー宣言関数から返された結果です。ファクトリはサービスと同じように動作します:

var factoryAsService = function(injection) {
  return new function(injection) {
    // Service content
  }
}

最も単純な考え方は次のとおりです。

  • サービスはシングルトンオブジェクトインスタンスです。コードにシングルトンオブジェクトを提供する場合は、サービスを使用します。
  • 工場はクラスです。コードにカスタムクラスを提供する場合は、ファクトリを使用します(すでにインスタンス化されているため、サービスでは実行できません)。

ファクトリの「クラス」の例は、コメントとプロバイダーの違いで提供されています。


サービスが使用されるたびにインスタンス化される場合、サービスはどのようにシングルトンになることができますか?私はそれのまわりで私の頭を得ることができます...
joe

サービスは、依存関係の解決中に一度だけインスタンス化され、インジェクターからサービスを要求すると、常に同じインスタンスを取得します。ここで簡単に確認できます:jsfiddle.net/l0co/sovtu55t/1、コンソールで実行してください。コンソールは、サービスが1回だけインスタンス化されていることを示しています。
Lukasz Frankowski、2015年

ああなるほど。私は文字通りnew MyService()何かができると期待していました:)
joe

33

この問題についての私の説明:

基本的に、前述のすべてのタイプ(サービス、ファクトリー、プロバイダーなど)は、昔ながらのグローバル変数と同様に、グローバル変数(もちろん、アプリケーション全体に対してグローバルです)を作成して構成しているだけです。

グローバル変数は推奨されませんが、これらのグローバル変数の実際の使用法は、関連するコントローラーに変数を渡すことにより、依存性注入を提供することです。

「グローバル変数」の値の作成には、多くの複雑なレベルがあります。

  1. 定数
    これは、他の言語の定数(JavaScriptにはないもの)と同様に、アプリケーション全体で変更してはならない実際の定数を定義します。

  2. これは変更可能な値またはオブジェクトであり、いくつかのグローバル変数として機能し、他のサービスまたはファクトリを作成するときに挿入することもできます(これらの詳細を参照)。ただし、これは「リテラル値」である必要があります。つまり、実際の値を書き出す必要があり、計算ロジックやプログラミングロジックを使用できません(つまり、39またはmyTextまたは{prop: "value"}は問題ありませんが、2 +2はそうではありません)。
  3. Factory
    より一般的な値で、すぐに計算できます。これは、値を計算するために必要なロジックを持つ関数をAngularJSに渡し、AngularJSがそれを実行することによって機能し、戻り値を名前付き変数に保存します。
    オブジェクト(サービスの場合と同様に機能する)または関数(コールバック関数として変数に保存される)を返すことができることに注意してください。
  4. サービス
    サービスは、値がオブジェクトである場合にのみ有効な、より簡素化されたバージョンのファクトリーであり、関数で直接(コンストラクターであるかのように)ロジックを記述し、宣言してアクセスすることができます。thisキーワードを使用したオブジェクトのプロパティ。
  5. プロバイダーfactoryの
    簡略化されたバージョンであるサービスとは異なり、プロバイダーは「グローバル」変数を初期化するより複雑ですがより柔軟な方法であり、最大の柔軟性はapp.configから値を設定するオプションです。 これは、thisキーワードを使用して宣言されたプロパティを持つ関数をproviderに渡すことにより、serviceproviderを組み合わせて使用​​するように機能します。thisキーワードは、から使用できます。 次に、ファイルを介して上記のプロパティを設定した後、AngularJSによって実行される個別の$ .get関数が必要です。この$ .get
    app.config
    app.config関数は、ファクトリーと同じように動作します 上記では、その戻り値は「グローバル」変数を初期化するために使用されます。

26

以下の私の理解は非常に簡単です。

ファクトリー:ファクトリー 内にオブジェクトを作成し、それを返すだけです。

サービス:

このキーワードを使用して関数を定義する標準関数があります。

プロバイダー:

$get定義したオブジェクトがあり、データを返すオブジェクトを取得するために使用できます。


工場とサービスを混同していませんか?サービスは、工場が戻る場所を作成します。
Flavien Volken 2014年

サービス名を注入可能な引数として宣言すると、関数のインスタンスが提供されます。つまり、新しいFunctionYouPassedToService()です。このオブジェクトインスタンスは、AngularJSが登録して後で必要に応じて他のサービス/コントローラーに挿入するサービスオブジェクトになります。// factory factorynameを注入可能な引数として宣言すると、module.factoryに渡された関数参照を呼び出すことによって返される値が提供されます。
sajan 2014年

わかりましたので、...角度に工場があるシングルトン「サービス」は、実際にある工場(共通のデザインパターンに関して)
Flavien Volken

25

Angular docsからの要約:

  • オブジェクトの作成方法を定義する5つのレシピタイプがあります:ValueFactoryServiceProviderおよびConstant
  • 工場サービスは、最も一般的に使用されるレシピです。それらの唯一の違いは、ファクトリがJavaScriptプリミティブと関数を生成できるのに対し、サービスレシピはカスタムタイプのオブジェクトに対してよりよく機能することです。
  • プロバイダーレシピは、コアレシピタイプであり、他のすべてのものは、その上にだけ糖衣構文です。
  • プロバイダーは最も複雑なレシピタイプです。グローバル構成を必要とする再利用可能なコードを構築しているのでない限り、それは必要ありません。

ここに画像の説明を入力してください


SOからの最良の回答:

https://stackoverflow.com/a/26924234/165673 (< - GOOD) https://stackoverflow.com/a/27263882/165673
https://stackoverflow.com/a/16566144/165673


20

すべての良い答えはすでに。ServiceFactoryについてもう少しポイントを追加したいと思います。サービス/工場の違いとともに。また、次のような質問をすることもできます。

  1. サービスまたは工場を使用する必要がありますか?違いは何ですか?
  2. 彼らは同じですか、同じ行動をしますか?

サービスとファクトリーの違いから始めましょう:

  1. どちらもシングルトンです。Angularがこれらを最初に依存関係として検出するたびに、サービス/ファクトリの単一のインスタンスが作成されます。インスタンスが作成されると、同じインスタンスが永久に使用されます。

  2. 動作のあるオブジェクトをモデル化するために使用できます。どちらもメソッド、内部状態変数などを持つことができます。ただし、そのコードの記述方法は異なります。

サービス:

サービスはコンストラクター関数であり、Angularはnewを呼び出してサービスをインスタンス化しますyourServiceName()。これはいくつかのことを意味します。

  1. 関数とインスタンス変数はのプロパティになります this
  2. 値を返す必要はありません。Angularがnew yourServiceName()を呼び出すと、配置thisしたすべてのプロパティを持つオブジェクトを受け取ります。

サンプルの例:

angular.service('MyService', function() {
  this.aServiceVariable = "Ved Prakash"
  this.aServiceMethod = function() {
    return //code
  };
});

AngularがこのMyServiceサービスを依存するコントローラーに注入すると、そのコントローラーはMyServiceMyService.aServiceMethod()などの関数を呼び出すことができるを取得します。

に注意してください this

構築されたサービスはオブジェクトなので、その中のメソッドは、呼び出されたときにこれを参照できます。

angular.service('ScoreKeeper', function($http) {
  this.score = 0;

  this.getScore = function() {
    return this.score;
  };

  this.setScore = function(newScore) {
    this.score = newScore;
  };

  this.addOne = function() {
    this.score++;
  };
});

ScoreKeeper.setScoreたとえば、サーバーからスコアを取得してスコアを初期化した場合、promiseチェーンを呼び出したくなるかもしれません。$http.get('/score').then(ScoreKeeper.setScore).これの問題は、バインドされてScoreKeeper.setScore呼び出され、エラーが発生することです。より良い方法はでしょう。これをサービスメソッドで使用するかどうかに関係なく、それらを呼び出す方法に注意してください。thisnull$http.get('/score').then(ScoreKeeper.setScore.bind(ScoreKeeper))

から値を返すService

JavaScriptコンストラクターの仕組みにより(i.e., an Object)constructor関数から複雑な値を返す場合、呼び出し元はこのインスタンスではなくそのオブジェクトを取得します。

あなたは基本的には、下記から工場の例をコピー&ペースト置き換えることができ、この意味factoryservice、それがうまくいきます:

angular.service('MyService', function($http) {
  var api = {};

  api.aServiceMethod= function() {
    return $http.get('/users');
  };
  return api;
});

したがって、Angularがnew MyService()を使用してサービスを構築すると、MyServiceインスタンスの代わりにそのAPIオブジェクトが取得されます。

これは複雑な値(オブジェクト、関数)の動作ですが、プリミティブ型の動作ではありません。

工場:

ファクトリーは、値を返すプレーンな古い関数です。戻り値は、ファクトリに依存するものに注入されるものです。Angularの典型的なファクトリパターンは、次のように、プロパティとして関数を持つオブジェクトを返すことです。

angular.factory('MyFactory', function($http) {
  var api = {};

  api.aFactoryMethod= function() {
    return $http.get('/users');
  };

  return api;
});

ファクトリー依存関係に注入された値は、ファクトリーの戻り値であり、オブジェクトである必要はありません。関数かもしれません

上記の1および2の質問に対する回答:

ほとんどの場合、すべてにファクトリーを使用することに固執します。彼らの行動は理解しやすいです。値を返すかどうかを決める選択肢はありません。さらに、間違った操作を行ってもバグが発生することはありません。

ただし、依存関係として挿入することについて話しているときは、「サービス」と呼んでいます。

サービス/ファクトリーの動作は非常によく似ており、どちらかで問題ないと言う人もいます。それは幾分正しいですが、ジョンパパのスタイルガイドのアドバイスに従い、工場に固執する方が簡単だと思います。**


16

さらに説明すると、サービスでは作成できないのに、ファクトリでは関数/プリミティブを作成できます。Epokkに基づくこのjsFiddleを確認してください:http ://jsfiddle.net/skeller88/PxdSP/1351/

ファクトリは、呼び出すことができる関数を返します。

myApp.factory('helloWorldFromFactory', function() {
  return function() {
    return "Hello, World!";
  };
});

ファクトリは、呼び出すことができるメソッドでオブジェクトを返すこともできます。

myApp.factory('helloWorldFromFactory', function() {
  return {
    sayHello: function() {
      return "Hello, World!";
    }
  };
});

サービスは、呼び出すことができるメソッドを持つオブジェクトを返します。

myApp.service('helloWorldFromService', function() {
  this.sayHello = function() {
     return "Hello, World!";
  };
});

詳細については、違いについて書いた投稿を参照してください。http//www.shanemkeller.com/tldr-services-vs-factories-in-angular/


16

良い答えはすでにありますが、私はこれを共有したいだけです。

まず第一に、プロバイダーは、を作成する方法/レシピですservice $ injectorによって注入されることを想定し(シングルトンオブジェクト)(AngulaJSがIoCパターンを処理する方法)。

そして、Value、Factory、Service、Constant(4つの方法)- プロバイダーの方法/レセプトに対する構文上の砂糖。

Service vs Factoryカバーされている部分がありますhttps : //www.youtube.com/watch?v=BLzNCkPn3ao

サービスとはnew実際にキーワードに関するものであり、私たちが知っているように4つのことを行います。

  1. 新しいオブジェクトを作成します
  2. にリンクします prototypeオブジェクトにます
  3. 接続する contextしますthis
  4. そして戻る this

そしてファクトリーはすべてファクトリー・パターンに関するものです-そのサービスのようなオブジェクトを返す関数が含まれています。

  1. 他のサービスを使用する機能(依存関係がある)
  2. サービスの初期化
  3. 遅延/遅延初期化

そして、このシンプルな/短いビデオ:プロバイダーもカバーしていますhttps : //www.youtube.com/watch?v=HvTZbQ_hUZY(工場からプロバイダーにどのように移行するかがわかります)

プロバイダーレシピは、アプリが完全に起動/初期化される前に、主にアプリ構成で使用されます。


14

これらのすべての投稿を読んだ後、それは私にとってさらに混乱を引き起こしました..しかし、それでもすべての情報は価値があります..最後に、単純な比較で情報を提供する次の表を見つけました

  • インジェクターは、レシピを使用して、サービスと特殊目的オブジェクトの2種類のオブジェクトを作成します。
  • オブジェクトの作成方法を定義する5つのレシピタイプがあります。値、ファクトリ、サービス、プロバイダー、定数です。
  • 工場とサービスは、最も一般的に使用されるレシピです。それらの唯一の違いは、ファクトリがJavaScriptプリミティブと関数を生成できるのに対し、サービスレシピはカスタムタイプのオブジェクトに対してより適切に機能することです。
  • プロバイダーレシピはコアレシピタイプであり、他のすべてのレシピは構文上の砂糖です。
  • プロバイダーは最も複雑なレシピタイプです。グローバル構成を必要とする再利用可能なコードを構築しているのでない限り、それは必要ありません。
  • コントローラを除くすべての特殊用途オブジェクトは、ファクトリレシピを介して定義されます。

ここに画像の説明を入力してください

そして、初心者のために理解してください:-これはユースケースを修正しないかもしれませんが、高レベルではこれはこれら3つのユースケースです。

  1. 角度モジュールで使用する場合は、構成関数をプロバイダーとして作成する必要があります

angular.module('myApp').config(function($testProvider){
$testProvider.someFunction();
})

  1. Ajaxコールまたはサードパーティ統合はサービスである必要があります
  2. データ操作については、ファクトリとして作成します

基本的なシナリオでは、factory&Serviceは同じように動作します。


13

AngularjSのオブジェクトファクトリのコードテンプレートとして私が思いついたいくつかのブロイラープレートコードを次に示します。説明のために、例としてCar / CarFactoryを使用しました。コントローラーのシンプルな実装コードを作成します。

     <script>
        angular.module('app', [])
            .factory('CarFactory', function() {

                /**
                 * BroilerPlate Object Instance Factory Definition / Example
                 */
                this.Car = function() {

                    // initialize instance properties
                    angular.extend(this, {
                        color           : null,
                        numberOfDoors   : null,
                        hasFancyRadio   : null,
                        hasLeatherSeats : null
                    });

                    // generic setter (with optional default value)
                    this.set = function(key, value, defaultValue, allowUndefined) {

                        // by default,
                        if (typeof allowUndefined === 'undefined') {
                            // we don't allow setter to accept "undefined" as a value
                            allowUndefined = false;
                        }
                        // if we do not allow undefined values, and..
                        if (!allowUndefined) {
                            // if an undefined value was passed in
                            if (value === undefined) {
                                // and a default value was specified
                                if (defaultValue !== undefined) {
                                    // use the specified default value
                                    value = defaultValue;
                                } else {
                                    // otherwise use the class.prototype.defaults value
                                    value = this.defaults[key];
                                } // end if/else
                            } // end if
                        } // end if

                        // update 
                        this[key] = value;

                        // return reference to this object (fluent)
                        return this;

                    }; // end this.set()

                }; // end this.Car class definition

                // instance properties default values
                this.Car.prototype.defaults = {
                    color: 'yellow',
                    numberOfDoors: 2,
                    hasLeatherSeats: null,
                    hasFancyRadio: false
                };

                // instance factory method / constructor
                this.Car.prototype.instance = function(params) {
                    return new 
                        this.constructor()
                                .set('color',           params.color)
                                .set('numberOfDoors',   params.numberOfDoors)
                                .set('hasFancyRadio',   params.hasFancyRadio)
                                .set('hasLeatherSeats', params.hasLeatherSeats)
                    ;
                };

                return new this.Car();

            }) // end Factory Definition
            .controller('testCtrl', function($scope, CarFactory) {

                window.testCtrl = $scope;

                // first car, is red, uses class default for:
                // numberOfDoors, and hasLeatherSeats
                $scope.car1     = CarFactory
                                    .instance({
                                        color: 'red'
                                    })
                                ;

                // second car, is blue, has 3 doors, 
                // uses class default for hasLeatherSeats
                $scope.car2     = CarFactory
                                    .instance({
                                        color: 'blue',
                                        numberOfDoors: 3
                                    })
                                ;
                // third car, has 4 doors, uses class default for 
                // color and hasLeatherSeats
                $scope.car3     = CarFactory
                                    .instance({
                                        numberOfDoors: 4
                                    })
                                ;
                // sets an undefined variable for 'hasFancyRadio',
                // explicitly defines "true" as default when value is undefined
                $scope.hasFancyRadio = undefined;
                $scope.car3.set('hasFancyRadio', $scope.hasFancyRadio, true);

                // fourth car, purple, 4 doors,
                // uses class default for hasLeatherSeats
                $scope.car4     = CarFactory
                                    .instance({
                                        color: 'purple',
                                        numberOfDoors: 4
                                    });
                // and then explicitly sets hasLeatherSeats to undefined
                $scope.hasLeatherSeats = undefined;
                $scope.car4.set('hasLeatherSeats', $scope.hasLeatherSeats, undefined, true);

                // in console, type window.testCtrl to see the resulting objects

            });
    </script>

簡単な例を示します。私は、緯度と経度を公開する「位置」オブジェクトを期待するいくつかのサードパーティライブラリを使用していますが、異なるオブジェクトプロパティを使用しています。ベンダーコードをハックしたくなかったので、渡していた「Position」オブジェクトを調整しました。

    angular.module('app')
.factory('PositionFactory', function() {

    /**
     * BroilerPlate Object Instance Factory Definition / Example
     */
    this.Position = function() {

        // initialize instance properties 
        // (multiple properties to satisfy multiple external interface contracts)
        angular.extend(this, {
            lat         : null,
            lon         : null,
            latitude    : null,
            longitude   : null,
            coords: {
                latitude: null,
                longitude: null
            }
        });

        this.setLatitude = function(latitude) {
            this.latitude           = latitude;
            this.lat                = latitude;
            this.coords.latitude    = latitude;
            return this;
        };
        this.setLongitude = function(longitude) {
            this.longitude          = longitude;
            this.lon                = longitude;
            this.coords.longitude   = longitude;
            return this;
        };

    }; // end class definition

    // instance factory method / constructor
    this.Position.prototype.instance = function(params) {
        return new 
            this.constructor()
                    .setLatitude(params.latitude)
                    .setLongitude(params.longitude)
        ;
    };

    return new this.Position();

}) // end Factory Definition

.controller('testCtrl', function($scope, PositionFactory) {
    $scope.position1 = PositionFactory.instance({latitude: 39, longitude: 42.3123});
    $scope.position2 = PositionFactory.instance({latitude: 39, longitude: 42.3333});
}) // end controller

;


12

このページとドキュメントを参照として使用する(前回見たときから大幅に改善されているようです)をして、プロバイダーの5つのフレーバーのうち4つを使用する次の実際の(-ish)ワールドデモをまとめました。バリュー、コンスタント、ファクトリー、本格的なプロバイダー。

HTML:

<div ng-controller="mainCtrl as main">
    <h1>{{main.title}}*</h1>
    <h2>{{main.strapline}}</h2>
    <p>Earn {{main.earn}} per click</p>
    <p>You've earned {{main.earned}} by clicking!</p>
    <button ng-click="main.handleClick()">Click me to earn</button>
    <small>* Not actual money</small>
</div>

アプリ

var app = angular.module('angularProviders', []);

// A CONSTANT is not going to change
app.constant('range', 100);

// A VALUE could change, but probably / typically doesn't
app.value('title', 'Earn money by clicking');
app.value('strapline', 'Adventures in ng Providers');

// A simple FACTORY allows us to compute a value @ runtime.
// Furthermore, it can have other dependencies injected into it such
// as our range constant.
app.factory('random', function randomFactory(range) {
    // Get a random number within the range defined in our CONSTANT
    return Math.random() * range;
});

// A PROVIDER, must return a custom type which implements the functionality 
// provided by our service (see what I did there?).
// Here we define the constructor for the custom type the PROVIDER below will 
// instantiate and return.
var Money = function(locale) {

    // Depending on locale string set during config phase, we'll
    // use different symbols and positioning for any values we 
    // need to display as currency
    this.settings = {
        uk: {
            front: true,
            currency: '£',
            thousand: ',',
            decimal: '.'
        },
        eu: {
            front: false,
            currency: '€',
            thousand: '.',
            decimal: ','
        }
    };

    this.locale = locale;
};

// Return a monetary value with currency symbol and placement, and decimal 
// and thousand delimiters according to the locale set in the config phase.
Money.prototype.convertValue = function(value) {

    var settings = this.settings[this.locale],
        decimalIndex, converted;

    converted = this.addThousandSeparator(value.toFixed(2), settings.thousand);

    decimalIndex = converted.length - 3;

    converted = converted.substr(0, decimalIndex) +
        settings.decimal +
        converted.substr(decimalIndex + 1);    

    converted = settings.front ?
            settings.currency + converted : 
            converted + settings.currency; 

    return converted;   
};

// Add supplied thousand separator to supplied value
Money.prototype.addThousandSeparator = function(value, symbol) {
   return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, symbol);
};

// PROVIDER is the core recipe type - VALUE, CONSTANT, SERVICE & FACTORY
// are all effectively syntactic sugar built on top of the PROVIDER construct
// One of the advantages of the PROVIDER is that we can configure it before the
// application starts (see config below).
app.provider('money', function MoneyProvider() {

    var locale;

    // Function called by the config to set up the provider
    this.setLocale = function(value) {
        locale = value;   
    };

    // All providers need to implement a $get method which returns
    // an instance of the custom class which constitutes the service
    this.$get = function moneyFactory() {
        return new Money(locale);
    };
});

// We can configure a PROVIDER on application initialisation.
app.config(['moneyProvider', function(moneyProvider) {
    moneyProvider.setLocale('uk');
    //moneyProvider.setLocale('eu'); 
}]);

// The ubiquitous controller
app.controller('mainCtrl', function($scope, title, strapline, random, money) {

    // Plain old VALUE(s)
    this.title = title;
    this.strapline = strapline;

    this.count = 0;

    // Compute values using our money provider    
    this.earn = money.convertValue(random); // random is computed @ runtime
    this.earned = money.convertValue(0);

    this.handleClick = function() { 
        this.count ++;
        this.earned = money.convertValue(random * this.count);
    };
});

作業デモ


12

この回答はトピック/質問に対処します

どのようにファクトリ、サービス、および定数—プロバイダーのレシピに加えて、単なる構文上の砂糖ですか?

または

どのように工場、サービス、プロバイダーが内部的に類似している

基本的に何が起こるか

あなたが作るときfactory()、それはあなたがセットfunctionプロバイダのに第二引数で提供$getし、(それを返すprovider(name, {$get:factoryFn }))、あなたが得るすべてはあるproviderが、以外にプロパティ/メソッドが存在しない$getというのは、provider(手段は、あなたがこれを設定することはできません)

工場のソースコード

function factory(name, factoryFn, enforce) {
    return provider(name, {
      $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
    });
};

これをservice()返すときに、factory()にfunctionを注入してconstructor(サービスで提供したコンストラクタのインスタンスを返す)、それを返します

サービスのソースコード

function service(name, constructor) {
    return factory(name, ['$injector', function($injector) {
      return $injector.instantiate(constructor);
    }]);
};

したがって、基本的にはどちらの場合でも、最終的にプロバイダー$ getを提供した関数に設定しますが、最初は構成ブロックのprovider()で提供できるので、$ get以外のものを追加できます。


11

私は優秀な答えをたくさん知っているが、私は使用しての私の経験を共有しなければならない
。1. serviceデフォルトのほとんどの場合
2. factoryサービスその特定のインスタンスを作成するために使用されます

// factory.js ////////////////////////////
(function() {
'use strict';
angular
    .module('myApp.services')
    .factory('xFactory', xFactoryImp);
xFactoryImp.$inject = ['$http'];

function xFactoryImp($http) {
    var fac = function (params) {
        this._params = params; // used for query params
    };

    fac.prototype.nextPage = function () {
        var url = "/_prc";

        $http.get(url, {params: this._params}).success(function(data){ ...
    }
    return fac;
}
})();

// service.js //////////////////////////
(function() {
'use strict';
angular
    .module('myApp.services')
    .service('xService', xServiceImp);
xServiceImp.$inject = ['$http'];

function xServiceImp($http) {  
    this._params = {'model': 'account','mode': 'list'};

    this.nextPage = function () {
        var url = "/_prc";

        $http.get(url, {params: this._params}).success(function(data){ ...
    }       
}
})();

そして使用:

controller: ['xFactory', 'xService', function(xFactory, xService){

        // books = new instance of xFactory for query 'book' model
        var books = new xFactory({'model': 'book', 'mode': 'list'});

        // accounts = new instance of xFactory for query 'accounts' model
        var accounts = new xFactory({'model': 'account', 'mode': 'list'});

        // accounts2 = accounts variable
        var accounts2 = xService;
... 

10

パーティーに少し遅れました。しかし、これは、ファクトリ、サービス、およびプロバイダーの方法論を使用してAngular JSカスタムサービスの開発について学びたい(または明確にしたい)方に役立つと思いました。

AngularJSカスタムサービスを開発するためのファクトリ、サービス、プロバイダーの方法論について明確に説明しているこのビデオに出くわしました。

https://www.youtube.com/watch?v=oUXku28ex-M

ソースコード:http : //www.techcbt.com/Post/353/Angular-JS-basics/how-to-develop-angularjs-custom-service

ここに投稿されたコードは、読者のために、上記のソースから直接コピーされています。

「ファクトリー」ベースのカスタムサービスのコードは次のとおりです(httpサービスの呼び出しに加えて、同期バージョンと非同期バージョンの両方に対応しています)。

var app = angular.module("app", []);
app.controller('emp', ['$scope', 'calcFactory',
  function($scope, calcFactory) {
    $scope.a = 10;
    $scope.b = 20;

    $scope.doSum = function() {
      //$scope.sum = calcFactory.getSum($scope.a, $scope.b); //synchronous
      calcFactory.getSum($scope.a, $scope.b, function(r) { //aynchronous
        $scope.sum = r;
      });
    };

  }
]);

app.factory('calcFactory', ['$http', '$log',
  function($http, $log) {
    $log.log("instantiating calcFactory..");
    var oCalcService = {};

    //oCalcService.getSum = function(a,b){
    //	return parseInt(a) + parseInt(b);
    //};

    //oCalcService.getSum = function(a, b, cb){
    //	var s = parseInt(a) + parseInt(b);
    //	cb(s);
    //};

    oCalcService.getSum = function(a, b, cb) { //using http service

      $http({
        url: 'http://localhost:4467/Sum?a=' + a + '&b=' + b,
        method: 'GET'
      }).then(function(resp) {
        $log.log(resp.data);
        cb(resp.data);
      }, function(resp) {
        $log.error("ERROR occurred");
      });
    };

    return oCalcService;
  }
]);

カスタムサービスの「サービス」方法論のコード(これは「ファクトリー」にかなり似ていますが、構文の観点とは異なります):

var app = angular.module("app", []);
app.controller('emp', ['$scope', 'calcService', function($scope, calcService){
	$scope.a = 10;
	$scope.b = 20;

	$scope.doSum = function(){
		//$scope.sum = calcService.getSum($scope.a, $scope.b);
		
		calcService.getSum($scope.a, $scope.b, function(r){
			$scope.sum = r;
		});		
	};

}]);

app.service('calcService', ['$http', '$log', function($http, $log){
	$log.log("instantiating calcService..");
	
	//this.getSum = function(a,b){
	//	return parseInt(a) + parseInt(b);
	//};

	//this.getSum = function(a, b, cb){
	//	var s = parseInt(a) + parseInt(b);
	//	cb(s);
	//};

	this.getSum = function(a, b, cb){
		$http({
			url: 'http://localhost:4467/Sum?a=' + a + '&b=' + b,
			method: 'GET'
		}).then(function(resp){
			$log.log(resp.data);
			cb(resp.data);
		},function(resp){
			$log.error("ERROR occurred");
		});
	};

}]);

カスタムサービスの「プロバイダー」方法論のコード(構成可能なサービスを開発する場合に必要です):

var app = angular.module("app", []);
app.controller('emp', ['$scope', 'calcService', function($scope, calcService){
	$scope.a = 10;
	$scope.b = 20;

	$scope.doSum = function(){
		//$scope.sum = calcService.getSum($scope.a, $scope.b);
		
		calcService.getSum($scope.a, $scope.b, function(r){
			$scope.sum = r;
		});		
	};

}]);

app.provider('calcService', function(){

	var baseUrl = '';

	this.config = function(url){
		baseUrl = url;
	};

	this.$get = ['$log', '$http', function($log, $http){
		$log.log("instantiating calcService...")
		var oCalcService = {};

		//oCalcService.getSum = function(a,b){
		//	return parseInt(a) + parseInt(b);
		//};

		//oCalcService.getSum = function(a, b, cb){
		//	var s = parseInt(a) + parseInt(b);
		//	cb(s);	
		//};

		oCalcService.getSum = function(a, b, cb){

			$http({
				url: baseUrl + '/Sum?a=' + a + '&b=' + b,
				method: 'GET'
			}).then(function(resp){
				$log.log(resp.data);
				cb(resp.data);
			},function(resp){
				$log.error("ERROR occurred");
			});
		};		

		return oCalcService;
	}];

});

app.config(['calcServiceProvider', function(calcServiceProvider){
	calcServiceProvider.config("http://localhost:4467");
}]);

最後に、上記のサービスのいずれかと連携するUI:

<html>
<head>
	<title></title>
	<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js" ></script>
	<script type="text/javascript" src="t03.js"></script>
</head>
<body ng-app="app">
	<div ng-controller="emp">
		<div>
			Value of a is {{a}},
			but you can change
			<input type=text ng-model="a" /> <br>

			Value of b is {{b}},
			but you can change
			<input type=text ng-model="b" /> <br>

		</div>
		Sum = {{sum}}<br>
		<button ng-click="doSum()">Calculate</button>
	</div>
</body>
</html>


10

明確にするために、AngularJSソースから、サービスがファクトリー関数を呼び出すだけで、プロバイダー関数を呼び出すことがわかります。

function factory(name, factoryFn) { 
    return provider(name, { $get: factoryFn }); 
}

function service(name, constructor) {
    return factory(name, ['$injector', function($injector) {
      return $injector.instantiate(constructor);
    }]);
}

9

簡単な方法でAngularJSでビジネスロジックを処理する3つの方法を議論してみましょう:(YaakovののコーセラAngularJSコースに触発さ

SERVICE

構文:

app.js

 var app = angular.module('ServiceExample',[]);
 var serviceExampleController =
              app.controller('ServiceExampleController', ServiceExampleController);
 var serviceExample = app.service('NameOfTheService', NameOfTheService);

 ServiceExampleController.$inject = ['NameOfTheService'] //protects from minification of js files

function ServiceExampleController(NameOfTheService){
     serviceExampleController = this;
     serviceExampleController.data = NameOfTheService.getSomeData();
 }

function NameOfTheService(){
     nameOfTheService = this;
     nameOfTheService.data = "Some Data";
     nameOfTheService.getSomeData = function(){
           return nameOfTheService.data;
     }     
}

index.html

<div ng-controller = "ServiceExampleController as serviceExample">
   {{serviceExample.data}}
</div>

サービスの特徴:

  1. 遅延インスタンス化:注入されない場合、インスタンス化されません。したがって、それを使用するには、モジュールに注入する必要があります。
  2. シングルトン:複数のモジュールに注入された場合、すべてが1つの特定のインスタンスにのみアクセスできます。これが、異なるコントローラ間でデータを共有するのに非常に便利な理由です。

工場

最初に構文を見てみましょう:

app.js

var app = angular.module('FactoryExample',[]);
var factoryController = app.controller('FactoryController', FactoryController);
var factoryExampleOne = app.factory('NameOfTheFactoryOne', NameOfTheFactoryOne);
var factoryExampleTwo = app.factory('NameOfTheFactoryTwo', NameOfTheFactoryTwo);

//first implementation where it returns a function
function NameOfTheFactoryOne(){
   var factory = function(){
      return new SomeService();
    }
   return factory;
}

//second implementation where an object literal would be returned
function NameOfTheFactoryTwo(){
   var factory = {
      getSomeService : function(){
          return new SomeService();
       }
    };
   return factory;
}

コントローラで上記の2つを使用します。

 var factoryOne = NameOfTheFactoryOne() //since it returns a function
 factoryOne.someMethod();

 var factoryTwo = NameOfTheFactoryTwo.getSomeService(); //accessing the object
 factoryTwo.someMethod();

工場の特徴:

  1. 工場の設計パターンに従います。ファクトリは、新しいオブジェクトまたは機能を生成する中心的な場所です。
  2. シングルトンだけでなく、カスタマイズ可能なサービスも生成します。
  3. この.service()メソッドは、常に同じタイプのサービス(シングルトン)を生成するファクトリであり、その動作を簡単に構成する方法はありません。その.service()方法は通常、設定をまったく必要としないもののショートカットとして使用されます。

プロバイダー

最初にもう一度構文を見てみましょう。

angular.module('ProviderModule', [])
.controller('ProviderModuleController', ProviderModuleController)
.provider('ServiceProvider', ServiceProvider)
.config(Config); //optional

Config.$inject = ['ServiceProvider'];
function Config(ServiceProvider) {
  ServiceProvider.defaults.maxItems = 10; //some default value
}


ProviderModuleController.$inject = ['ServiceProvider'];
function ProviderModuleController(ServiceProvider) {
  //some methods
}

function ServiceProvider() {
  var provider = this;

  provider.defaults = {
    maxItems: 10
  };

  provider.$get = function () {
    var someList = new someListService(provider.defaults.maxItems);

    return someList;
  };
}

}

プロバイダーの機能:

  1. プロバイダーは、Angularでサービスを作成する最も柔軟な方法です。
  2. 動的に構成可能なファクトリーを作成できるだけでなく、ファクトリーを使用するときにプロバイダーメソッドを使用すると、アプリケーション全体のブートストラップ時に一度だけファクトリーをカスタム構成できます。
  3. ファクトリはカスタム設定でアプリケーション全体で使用できます。つまり、アプリケーションを起動する前にこのファクトリを構成できます。実際、角度のあるドキュメントでは、.serviceまたは.factoryメソッドでサービスを構成するときに、プロバイダーメソッドが実際に舞台裏で実行されることが言及されています。
  4. $get直接プロバイダインスタンスに取り付けられている機能です。その関数はファクトリ関数です。つまり、メソッドに提供するために使用するものと同じ.factoryです。その機能では、独自のサービスを作成します。この$getプロパティは関数であり、プロバイダーをプロバイダーにしますAngularJSは、プロバイダーが$ getプロパティを持ち、その値がAngularがファクトリー関数として扱う関数であることを期待しています。しかし、このプロバイダー全体のセットアップを非常に特別なものにしているのは、configサービスプロバイダー内にオブジェクトを提供できることであり、通常は、アプリケーション全体を構成できるステップで後で上書きできるデフォルトが付属しています。

7

ファクトリ:実際にファクトリ内にオブジェクトを作成して返すファクトリ。
service: thisキーワードを使用して関数を定義する標準関数のみのサービス。
プロバイダー:プロバイダーには定義した$ getがあり、データを返すオブジェクトを取得するために使用できます。


7

基本的に、プロバイダー、ファクトリー、サービスはすべてサービスです。ファクトリは、必要なものが$ get()関数のみの場合のサービスの特殊なケースであり、少ないコードでそれを記述できます。

サービス、ファクトリー、プロバイダーの主な違いは、それらの複雑さです。サービスは最も単純な形式であり、ファクトリーはもう少し堅牢であり、プロバイダーは実行時に構成可能です。

次に、それぞれを使用するタイミングの概要を示します。

工場:提供する値は、他のデータに基づいて計算する必要があります。

サービス:メソッドを使用してオブジェクトを返しています。

プロバイダー:構成フェーズ中に、作成される前に作成されるオブジェクトを構成できるようにする必要があります。アプリが完全に初期化される前に、主にアプリ構成でプロバイダーを使用します。


えーと。Value、Factory、Service、Constant —プロバイダーのレシピに加えて、単なる構文上の砂糖です。Angularjsドキュメント-プロバイダー
Sudarshan_SMD

はい、同意します
。angular4では

4

1.Servicesは、必要に応じて作成されるシングルトンオブジェクトであり、アプリケーションのライフサイクルが終了する(ブラウザーが閉じられる)までクリーンアップされません。コントローラーは、不要になると破棄され、クリーンアップされます。

2.サービスを作成する最も簡単な方法は、factory()メソッドを使用することです。factory()メソッドを使用すると、サービス関数とサービスデータを含むオブジェクトを返すことにより、サービスを定義できます。サービス定義関数は、$ httpや$ qなどの注入可能なサービスを配置する場所です。例:

angular.module('myApp.services')
.factory('User', function($http) { // injectables go here
var backendUrl = "http://localhost:3000"; var service = {
    // our factory definition
user: {},
setName: function(newName) {
      service.user['name'] = newName;
    },
setEmail: function(newEmail) { service.user['email'] = newEmail;
},
save: function() {
return $http.post(backendUrl + '/users', { user: service.user
}); }
};
return service; });

アプリでのfactory()の使用

実行時に必要な場所に注入するだけなので、アプリケーションでファクトリを使用するのは簡単です。

angular.module('myApp')
.controller('MainController', function($scope, User) {
  $scope.saveUser = User.save;
});
  1. 一方、service()メソッドを使用すると、コンストラクター関数を定義してサービスを作成できます。未加工のJavaScriptオブジェクトの代わりに、プロトタイプオブジェクトを使用してサービスを定義できます。factory()メソッドと同様に、関数定義でインジェクタブルも設定します。
  2. サービスを作成する最低レベルの方法は、provide()メソッドを使用することです。これは、.config()関数を使用して構成できるサービスを作成する唯一の方法です。以前のtoメソッドとは異なり、定義済みのthis。$ get()関数定義で注入可能オブジェクトを設定します。

-3

構文糖は違いですです。プロバイダーのみが必要です。または言い換えれば、プロバイダーのみが実際の角度であり、他のすべてのものは(コードを削減するために)導出されます。Value()と呼ばれる単純なバージョンもあり、これは値だけを返し、計算や関数は返しません。値もプロバイダーから派生しています!

では、なぜこのような複雑な問題が発生するのか、なぜプロバイダーを使用して他のすべてを忘れないのでしょうか。それは私たちがコードを簡単に書き、より良いコミュニケーションをするのを助けることになっています。そして、舌のほほえみの返答は、それが複雑になるほど、フレームワークをよりよく売ることになります。


  • 値を返すことができるプロバイダー=値
  • 単にインスタンス化して返すことができるプロバイダー=ファクトリー(+値)
  • インスタンス化+何かを実行できるプロバイダー=サービス(+ファクトリー、+値)
  • プロバイダー=は$ get(+ Factory、+ Service、+ Value)と呼ばれるプロパティを含む必要があります

角度注入は、この結論に到達する最初のヒントになります。

"$ injectorは、サービスではなく、プロバイダーではなくプロバイダーによって定義されたオブジェクトインスタンスを取得するために使用されます。

「Angularサービスはサービスファクトリによって作成されます。これらのサービスファクトリは、サービスプロバイダーによって作成された関数です。サービスプロバイダーはコンストラクター関数です。インスタンス化されると、プロパティを含める必要があります。 $ getと呼ばれ、サービスファクトリ関数を保持します。」

したがって、マスタープロバイダーとインジェクター、およびすべてが適切に配置されます。そして、TypeServiceでは、IServiceProviderから継承することでプロバイダーに$ getを実装できるようになると興味深いものになります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.