service教學 AngularJS:服務與提供商vs工廠




angularjs scope service (24)

對我來說,當我意識到它們都以相同的方式工作時,啟示出現了:通過運行一次,存儲它們獲得的值,然後在通過依賴注入引用時咳嗽相同的存儲值

說我們有:

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

三者之間的區別在於:

  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提供者的原因。

AngularJS中的ServiceProviderFactory之間有什麼區別?


已有好的答案,但我只是想分享這個。

首先:提供者是創建service(單例對象)的方式/配方,假設由$ injector注入(AngulaJS如何處理IoC模式)。

價值,工廠,服務和常數(4種方式) - 提供者方式/接受的語法糖。

Service vs Factory部分已覆蓋:https://www.youtube.com/watch?v=BLzNCkPn3ao

服務完全是關於new關鍵字實際上我們知道4件事:

  1. 創造全新的對象
  2. 將其鏈接到其prototype對象
  3. 連接contextthis
  4. 並返回 this

工廠是關於工廠模式的 - 包含返回像服務這樣的對象的函數。

  1. 使用其他服務的能力(有依賴性)
  2. 服務初始化
  3. 延遲/延遲初始化

這個簡單/短視頻:也包括提供商https://www.youtube.com/watch?v=HvTZbQ_hUZYhttps://www.youtube.com/watch?v=HvTZbQ_hUZY(你看到它們可以看到它們從工廠到提供商的方式)

在應用程序完全啟動/初始化之前,提供程序配方主要用於應用程序配置中。


閱讀完所有這些帖子之後,它給我帶來了更多的困惑..但仍然都是值得信息的......最後我發現下面的表格會給出簡單的比較信息

  • 注入器使用配方來創建兩種類型的對象:服務和專用對象
  • 有五種配方類型定義瞭如何創建對象:Value,Factory,Service,Provider和Constant。
  • 工廠和服務是最常用的食譜。它們之間的唯一區別是Service配方更適合自定義類型的對象,而Factory可以生成JavaScript原語和函數。
  • 提供者配方是核心配方類型,所有其他配方只是語法糖。
  • 提供者是最複雜的配方類型。除非您正在構建需要全局配置的可重用代碼,否則您不需要它。
  • 除Controller外的所有特殊用途對像都是通過工廠配方定義的。

並且對於初學者的理解: -這可能不正確的用例,但在高級別,這是這三個用例。

  1. 如果要在角度模塊中使用配置功能,則應創建為提供者

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

  1. Ajax調用或第三方集成需要服務
  2. 對於數據操作,將其創建為工廠

對於基本方案,工廠和服務的行為相同。


所有服務都是單身人士 ; 他們每個應用程序實例化一次。 它們可以是任何類型 ,無論是原始類型,對象文字,函數,還是自定義類型的實例。

valuefactoryserviceconstantprovider方法都是提供者。 他們教Injector如何實例化服務。

最詳細,但也是最全面的是提供者食譜。 剩下的四種食譜類型 - 價值,工廠,服務和常數 - 只是提供者食譜之上的語法糖

  • Value Recipe是最簡單的情況,您可以自己實例化服務並向注入器提供實例化值
  • Factory配方為Injector提供了一個工廠函數,它在需要實例化服務時調用。 調用時, 工廠函數創建並返回服務實例。 服務的依賴關係作為函數的參數注入。 因此,使用此配方可添加以下功能:
    • 能夠使用其他服務(具有依賴性)
    • 服務初始化
    • 延遲/延遲初始化
  • 服務配方幾乎與工廠配方相同,但這裡Injector使用new運算符而不是工廠函數調用構造函數。
  • 提供者食譜通常是矯枉過正的 。 它允許您配置工廠的創建,從而增加了一層間接。

    只有在要為應用程序範圍的配置公開API時才應使用Provider配方,該API必須在應用程序啟動之前進行。 這通常只適用於可重用服務,其行為可能需要在應用程序之間略有不同。

  • Constant配方就像Value配方一樣,除了它允許您定義配置階段中可用的服務。 比使用Value配方創建的服務早。 與Values不同,它們不能使用decorator進行decorator
請參閱提供商文檔


只是為了澄清一些事情,從AngularJS源代碼中,您可以看到服務只調用工廠函數,而工廠函數又調用提供者函數:

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

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

JS小提琴演示

factory / service / provider “Hello world”示例:

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>


工廠:工廠實際上在工廠內創建一個對象並將其返回。
service:您只有一個使用this關鍵字定義函數的標準函數的服務。
provider:提供者有一個你定義的$ get,它可以用來獲取返回數據的對象。


這個答案解決了主題/問題

工廠,服務和常數 - 如何只是提供者食譜之上的語法糖?

要么

工廠,服務和供應商如何內部simailar

基本上會發生什麼

當你犯了一個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()它返回時,你提供一個工廠()function注入constructor(返回你在服務中提供的構造函數的實例)並返回它

源代碼服務

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

因此,基本上在這兩種情況下,您最終都會將提供者$ get設置為您提供的函數,但是您可以提供除$ get之外的任何內容,因為您最初可以在provider()中為config塊提供


在與提供商玩遊戲時我發現了一些有趣的東西

對於服務提供者而言,注射劑的可見性與服務和工廠的可見性不同。如果聲明AngularJS為“常量”(例如myApp.constant('a', 'Robert');),則可以將其註入服務,工廠和提供程序。

但是如果你聲明一個AngularJS“值”(例如。,myApp.value('b', {name: 'Jones'});),你可以將它注入服務和工廠,但不能注入提供者創建函數。但是,您可以將其註入$get為您的提供程序定義的函數中。AngularJS文檔中提到了這一點,但很容易錯過。您可以在值和常量方法部分的%提供頁面上找到它。

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>

從本質上講,提供商,工廠和服務都是服務。工廠是服務的一個特例,只需要一個$ get()函數,允許你用更少的代碼編寫它。

服務,工廠和供應商之間的主要區別在於其複雜性。服務是最簡單的形式,工廠更健壯,供應商可在運行時配置。

以下是何時使用每個的摘要:

工廠:您提供的價值需要根據其他數據計算。

服務:您正在使用方法返回一個對象。

提供程序:您希望能夠在配置階段配置將在創建之前創建的對象。在應用程序完全初始化之前,主要在應用程序配置中使用提供程序。


從AngularJS郵件列表中,我得到了一個驚人的線程 ,解釋了服務與工廠與提供商及其註入使用情況。 編譯答案:

服務

語法: module.service( 'serviceName', function );
結果:將serviceName聲明為可注入參數時,將為您提供該函數的實例。 換句話說, new FunctionYouPassedToService()

工廠

語法: module.factory( 'factoryName', function );
結果:當將factoryName聲明為injectable參數時,將通過調用傳遞給module.factory的函數引用來提供返回的值

供應商

語法: module.provider( 'providerName', function );
結果:當將providerName聲明為可注入參數時,將為您提供 (new ProviderFunction()).$get() 。 在調用$ get方法之前實例化構造函數 - ProviderFunction是傳遞給module.provider的函數引用。

提供商的優勢在於可以在模塊配置階段配置它們。

請參閱here了解提供的代碼。

這是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是一個負責創造價值的功能。 請注意,工廠函數可以請求其他依賴項。

但是如果你想成為更多的OO並擁有一個名為Greeter的課程怎麼辦?

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

然後要實例化你必須寫

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

然後我們可以在這樣的控制器中要求'greeter'

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');
}

作為旁注, servicefactoryvalue都來自提供商。

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;
  });
};

所有的好答案已經。我想在服務工廠上增加幾點。隨著服務/工廠之間的差異。人們也可以有這樣的問題:

  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服務注入依賴於它的控制器時,該控制器將獲得MyService可以調用函數的控件,例如MyService.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將被this綁定調用null並且您將獲得錯誤。更好的方法是$http.get('/score').then(ScoreKeeper.setScore.bind(ScoreKeeper))。無論您是否選擇在服務方法中使用此方法,請小心如何調用它們。

從a返回一個值Service

由於JavaScript構造函數的工作方式,如果(ie, an Object)constructor函數返回複雜值,調用者將獲取該Object而不是此實例。

這意味著您基本上可以從下面複製粘貼工廠示例,替換factoryservice,它將工作:

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

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

因此,當Angular使用新的MyService()構造您的服務時,它將獲得該api對象而不是MyService實例。

這是任何復雜值(對象,函數)的行為,但不適用於基本類型。

工廠:

工廠是一個返回值的普通舊函數。返回值是注入依賴於工廠的東西的東西。Angular中的典型工廠模式是返回一個具有屬性的對象,如下所示:

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

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

  return api;
});

工廠依賴項的注入值是工廠的返回值,它不必是對象。它可能是一種功能

以上1和2個問題的答案:

在大多數情況下,只需堅持使用工廠的一切。他們的行為更容易理解。沒有選擇是否返回一個值,而且,如果你做錯了,就不會引入錯誤。

不過,當我談到將它們作為依賴項注入時,我仍將它們稱為“服務”。

服務/工廠行為非常相似,有些人會說任何一個都很好。這有點真實,但我發現更容易遵循John Papa的風格指南的建議,只是堅持工廠。**


我知道很多優秀的答案,但我必須分享我的使用經驗
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;
... 

我對此事的澄清:

基本上所有提到的類型(服務,工廠,提供商等)只是創建和配置全局變量(當然對於整個應用程序是全局變量),就像舊的全局變量一樣。

雖然不建議使用全局變量,但這些全局變量的實際用途是通過將變量傳遞給相關控制器來提供依賴注入

創建“全局變量”的值有很多級別的複雜性:

  1. 不變
    這定義了一個在整個應用程序中不應該修改的實際常量,就像其他語言中的常量一樣(JavaScript缺少的東西)。

  2. 這是一個可修改的值或對象,它可以作為一些全局變量,甚至可以在創建其他服務或工廠時注入(參見上文)。但是,它必須是一個“ 字面值 ”,這意味著必須寫出實際值,並且不能使用任何計算或編程邏輯(換句話說39myText{prop:“value”}都可以,但是2 + 2不是)。
  3. 工廠
    更通用的值,可以立即計算。它的工作原理是將函數傳遞給AngularJS,其中包含計算值所需的邏輯,AngularJS執行它,並將返回值保存在命名變量中。
    請注意,可以返回一個對象(在這種情況下它將起到類似於服務的作用)或一個函數(將作為回調函數保存在變量中)。
  4. 服務
    服務是一個更精簡的工廠版本,僅當值是一個對象時才有效,它允許直接在函數中編寫任何邏輯(就好像它是一個構造函數),以及聲明和訪問使用this關鍵字的對象屬性。
  5. 提供程序
    與作為工廠簡化版本的服務不同,提供程序是一種更複雜但更靈活的初始化“全局”變量的方法,最大的靈活性是從app.config設置值的選項。
    它的工作方式類似於使用服務提供者的組合,通過向提供者傳遞一個函數,該函數具有使用this關鍵字聲明的屬性,可以從中使用app.config
    然後它需要一個單獨的$ .get函數,該函數由AngularJS在通過app.config文件設置上述屬性後執行,並且此$ .get函數的行為與工廠一樣 上面,其返回值用於初始化“全局”變量。

另外一個澄清是工廠可以創建函數/原語,而服務則不能。看看這個jsFiddle基於Epokk的: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/http://www.shanemkeller.com/tldr-services-vs-factories-in-angular/


對我來說,理解差異的最好和最簡單的方法是:

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
  }
}

最簡單的思考方式如下:

  • 服務是一個單例對象實例。如果要為代碼提供單例對象,請使用服務。
  • 工廠是一個班級。如果要為代碼提供自定義類,請使用工廠(由於已經實例化,因此無法使用服務)。

工廠的“類”示例在評論中提供,以及提供商差異。


1.服務是在必要時創建的單例對象,在應用程序生命週期結束之前(瀏覽器關閉時)永遠不會被清除。控制器在不再需要時被銷毀並清理乾淨。

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()方法類似,我們還將在函數定義中設置injectables。
  2. 創建服務的最低級別方法是使用provide()方法。這是創建我們可以使用.config()函數配置的服務的唯一方法。與前面的方法不同,我們將在一個定義的。$ get()函數定義中設置注入。

docs.angularjs.org/guide/providers摘要:

  • 有五種配方類型定義瞭如何創建對象:ValueFactoryServiceProviderConstant
  • 工廠服務是最常用的食譜。它們之間的唯一區別是Service配方更適合自定義類型的對象,而Factory可以生成JavaScript原語和函數。
  • 供應商的食譜是核心配方類型和所有其他的人都在它只是語法糖。
  • 提供者是最複雜的配方類型。除非您正在構建需要全局配置的可重用代碼,否則您不需要它。

來自SO的最佳答案:

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


正如幾個人在這裡正確指出的那樣,工廠,提供商,服務,甚至價值和常數都是同一件事的版本。您可以將更一般的內容剖析provider到所有這些中。像這樣:

這是這張圖片來自的文章:


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'的任何屬性。

現在讓我們在回調函數中添加一些“私有”變量。 這些不能直接從控制器訪問,但我們最終會在'service'上設置一些getter / setter方法,以便在需要時能夠改變這些'private'變量。

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;
});

在這裡你會注意到我們沒有將這些變量/函數附加到'service'。 我們只是創建它們以便以後使用或修改它們。

  • baseUrl是iTunes API所需的基本URL
  • _artist是我們想要查找的藝術家
  • _finalUrl是我們將調用iTunes的最終完全構建的URL
  • makeUrl是一個創建和返回我們的iTunes友好URL的函數。

現在我們的助手/私有變量和函數已經到位,讓我們為'service'對象添加一些屬性。 無論我們提供什麼'服務'都可以直接在我們通過'myFactory'的控制器中使用。

我們將創建setArtist和getArtist方法,只返回或設置藝術家。 我們還將創建一個方法,使用我們創建的URL調用iTunes API。 一旦數據從iTunes API返回,此方法將返回一個承諾。 如果您在AngularJS中沒有使用承諾的經驗,我強烈建議您深入了解它們。

以下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數據一起完成後才設置$ scope.data.artistData。 你會注意到我們的控制器非常“薄”(這是一個很好的編碼實踐)。 我們所有的邏輯和持久數據都位於我們的服務中,而不是我們的控制器中。

2)服務
在處理創建服務時,最重要的事情可能是它使用'new'關鍵字進行實例化。 對於JavaScript JavaScript專家來說,這應該會給你一個關於代碼本質的一個很大的暗示。 對於那些JavaScript背景有限的人或那些不太熟悉'new'關鍵字實際執行者的人,讓我們回顧一下最終將幫助我們理解服務性質的一些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()時,解釋器會說“好了,我將查看我們剛剛創建的'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;
}

現在了解'new'關鍵字在JavaScript中的實際功能,在AngularJS中創建服務應該更容易理解。

創建服務時要了解的最重要的事情是知道服務是使用'new'關鍵字實例化的。 將這些知識與上面的示例相結合,您現在應該認識到您將把屬性和方法直接附加到'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;
  }

});

現在就像我們的工廠一樣,setArtist,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)提供者

關於Providers最重要的事情是,它們是您可以傳遞到應用程序的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;
  }
}

*如果上述代碼的任何部分令人困惑,請查看工廠部分,我在其中解釋了它的更多細節。

您可以將提供商視為包含三個部分。 第一部分是稍後將修改/設置的“私有”變量/函數(如上所示)。 第二部分是app.config函數中可用的變量/函數,因此可以在其他任何地方可用之前進行更改(如上所示)。 重要的是要注意這些變量需要附加到'this'關鍵字。 在我們的示例中,只有'thingFromConfig'可以在app.config中進行更改。 第三部分(如下所示)是將“myProvider”服務傳遞到特定控制器時控制器中可用的所有變量/函數。

使用Provider創建服務時,控制器中唯一可用的屬性/方法是從$ 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
    }
  }

現在完整的Provider代碼看起來像這樣

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
    }
  }
});

就像在我們的工廠和服務中一樣,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;
});

如前所述,使用Provider創建服務的重點是能夠在將最終對像傳遞給應用程序的其餘部分之前通過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中時,它將是'這句話被設置......'。


下面是一些Broilerplate代碼,我將它作為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>

這是一個更簡單的例子。我正在使用一些第三方庫,這些庫期望“位置”對象暴露緯度和經度,但是通過不同的對象屬性。我不想破解供應商代碼,所以我調整了我傳遞的“位置”對象。

    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

;


派對遲到了。但我認為這對於谁愿意學習(或明確)使用工廠,服務和提供商方法開發Angular JS Custom Services更有幫助。

我看到了這個視頻,它清楚地解釋了開發AngularJS Custom Services的工廠,服務和提供商方法:

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

源代碼:http://www.techcbt.com/Post/353/Angular-JS-basics/how-to-develop-angularjs-custom-servicehttp://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>


對於新手而言,這是一個非常令人困惑的部分,我試圖用簡單的詞語來澄清它

AngularJS服務:用於與控制器中的服務引用共享實用程序功能。服務本質上是單例,因此對於一個服務,在瀏覽器中只創建一個實例,並在整個頁面中使用相同的引用。

在服務中,我們使用對象創建函數名稱作為屬性。

AngularJS Factory:Factory的目的也與Service相同,但在這種情況下,我們創建一個新對象並添加函數作為此對象的屬性,最後我們返回此對象。

AngularJS Provider:這個目的也是一樣的但是Provider提供了它的$ get函數的輸出。

http://www.dotnetfunda.com/articles/show/3156/difference-between-angularjs-service-factory-and-provider解釋了定義和使用服務,工廠和提供商的問題http://www.dotnetfunda.com/articles/show/3156/difference-between-angularjs-service-factory-and-provider


基於內存目的,控制器僅在需要時才被實例化,而在不需要時則被丟棄。因此,每次切換路徑或重新加載頁面時,Angular都會清理當前控制器。然而,服務提供了一種在應用程序的生命週期內保持數據的方法,同時它們也可以以一致的方式在不同的控制器上使用。

Angular為我們提供了三種創建和註冊自己服務的方法。

1)工廠

2)服務

3)提供者

工廠:工廠是一個簡單的功能,允許您在創建對象之前添加一些邏輯。它返回創建的對象。

它只是一個像類一樣的函數集合。因此,當您使用構造函數時,它可以在不同的控制器中實例化。

服務:服務是一個構造函數,它使用new關鍵字創建對象。您可以使用此關鍵字向服務對象添加屬性和函數。與工廠不同,它不會返回任何東西。

它是一個單例對象。需要在整個應用程序中共享單個對象時使用它。例如,經過身份驗證的用戶詳細信息

提供者:提供者用於創建可配置的服務對象。它使用$ get()函數返回值。

在服務對象可用之前,需要為服務對象提供模塊化配置。

運行以下代碼並查看輸出。

<!DOCTYPE html>
<html ng-app="app">
<head>
    <script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.min.js"></script>
    <meta charset=utf-8 />
    <title>JS Bin</title>
</head>
<body ng-controller="MyCtrl">
    {{serviceOutput}}
    <br/><br/>
    {{factoryOutput}}
    <br/><br/>
    {{providerOutput}}
    <script>
        var app = angular.module( 'app', [] );
        var MyFunc = function() {
            this.name = "default name";
            this.$get = function() {
                this.name = "new name"
                return "Hello from MyFunc.$get(). this.name = " + this.name;
            };
            return "Hello from MyFunc(). this.name = " + this.name;
        };
        // returns the actual function
        app.service( 'myService', MyFunc );
        // returns the function's return value
        app.factory( 'myFactory', MyFunc );
        // returns the output of the function's $get function
        app.provider( 'myProv', MyFunc );
        function MyCtrl( $scope, myService, myFactory, myProv ) {
            $scope.serviceOutput = "myService = " + myService;
            $scope.factoryOutput = "myFactory = " + myFactory;
            $scope.providerOutput = "myProvider = " + myProv;
        }
    </script>
</body>
</html>





angularjs-provider