成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

AngularJS:factory,service與provider的區(qū)別

lanffy / 1772人閱讀

摘要:首先創(chuàng)建我們的構(gòu)造函數(shù)這是一個典型的構(gòu)造函數(shù)。所以,我們首先知道的就是無論我們是否能夠在代碼里面看見,構(gòu)造函數(shù)是會返回一個對象的。

翻譯自 http://tylermcginnis.com/angularjs-factory-vs-service-vs-provider/

當你開始使用Angular的時候,你會發(fā)現(xiàn),你總是會讓你的控制器和作用域充滿各種不必要的邏輯。你應(yīng)該早點意識到一個控制器應(yīng)該是很簡潔精煉的;同時大多數(shù)的商業(yè)邏輯和一些重復(fù)性的數(shù)據(jù)都應(yīng)該要存儲到服務(wù)中。一天我在Stack Overflow上看到一些問題說是考慮將重復(fù)性的數(shù)據(jù)放在控制器里,但是,這不是這不是一個控制器應(yīng)該有的目的。如果為了內(nèi)存需要,控制器就應(yīng)該在需要他們的時候?qū)嵗?,在不需要的時候就取消掉。因此,Angular在你每次切換路由的時候,就會清理當前的控制器。但是呢,服務(wù)為我們提供了一種長期存儲應(yīng)用數(shù)據(jù)的方式,同時,也可以在不同的控制器之間統(tǒng)一的使用服務(wù)。

Angular為我們提供了三種創(chuàng)建服務(wù)的方式:

1、Factory
2、Service
3、Provider

先簡單介紹一下

一、當使用factory來創(chuàng)建服務(wù)的時候,相當于新創(chuàng)建了一個對象,然后在這個對象上新添屬性,最后返回這個對象。當把這個服務(wù)注入控制器的時候,控制器就可以訪問在那個對象上的屬性了。

app.factory("MyFactory", function () {
        var _artist = "",
            service = {};

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

        return service;
    })
    .controller("myFactoryCtrl", [
        "$scope", "MyFactory",
        function ( $scope, MyFactory ) {
            $scope.artist = MyFactory.getArtist();
        }]);

二、當使用service創(chuàng)建服務(wù)的時候,相當于使用new關(guān)鍵詞進行了實例化。因此,你只需要在this上添加屬性和方法,然后,服務(wù)就會自動的返回this。當把這個服務(wù)注入控制器的時候,控制器就可以訪問在那個對象上的屬性了。

app.service("MyService", function () {
        var _artist = "";
    
        this.getArtist = function () {
            return _artist;
        };
    })
    .controller("myServiceCtrl", [
        "$scope", "MyService",
        function ( $scope, MyService ) {
            $scope.artist = MyService.getArtist();
        }]);

三、provider是唯一一種可以創(chuàng)建用來注入到config()函數(shù)的服務(wù)的方式。想在你的服務(wù)啟動之前,進行一些模塊化的配置的話,就使用provider。

app.provider("MyProvider", function () {

        // 只有直接添加在this上的屬性才能被config函數(shù)訪問
        this._artist = "";
        this.thingFromConfig = "";

        // 只有$get函數(shù)返回的屬性才能被控制器訪問
        this.$get = function () {
            var that = this;

            return {
                getArtist: function () {
                    return that._artist;
                },
                thingFromConfig: that.thingFromConfig
            };
        };
    })
    .config(["MyProvider", function ( MyProvider ) {
        MyProvider.thingFormConfig = "this is set in config()";
    }])
    .controller("myProviderCtrl", [
        "$scope", "MyProvider",
        function ( $scope, MyProvider ) {
            $scope.artist = MyProvider.getArtist();
        }]);
下面我們來詳細說明

為了詳細的說明這三種方式的不同之處,我們分別使用這三種方式來創(chuàng)建同一個服務(wù)。這個服務(wù)將會用到iTunes API以及promise的$q。

使用factory

要創(chuàng)建和配置服務(wù),最普通的做法就是使用factory。就像上面簡單說明的那樣,這里也沒有太多要說明的地方,就是創(chuàng)建一個對象,然后為他添加屬性和方法,最后返回這個對象。當把這個服務(wù)注入控制器的時候,控制器就可以訪問在那個對象上的屬性了。一個很普通的例子就像下面那樣。

首先我們創(chuàng)建一個對象,然后返回這個對象。

app.factory("MyFactory", function () {
    var service = {};
    
    return service;
});

現(xiàn)在,我們添加到service上的任何屬性,只要將MyFactory注入到控制器,控制器就都可以訪問了。

現(xiàn)在,我們添加一些私有屬性到回調(diào)函數(shù)里,雖然不能從控制器里直接訪問這些變量,但是最終我們會提供一些gettersetter方法到service上以便于我們在需要的時候修改這些屬性。

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

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

        return service;
    }]);

你應(yīng)該注意到了,我們沒有把這些屬性和方法添加到service對象上去。我們現(xiàn)在只是先簡單的創(chuàng)建出來,以便于待會兒使用或者修改。

baseUrl是iTunes API需要的基本URL

_artist是我們需要查找的藝術(shù)家

_finalUrl是最終向iTunes發(fā)送請求的URL

makeUrl是一個用來創(chuàng)建返回我們最終的URL的函數(shù)

既然我們的輔助變量和函數(shù)都創(chuàng)建好了,那么,就往service添加一些屬性吧。我們在service上添加的任何屬性,只要服務(wù)注入了控制器中,那么,控制器就可以訪問這些屬性。

我們要創(chuàng)建一個setArtist()getArtist()函數(shù)來設(shè)置以及取得藝術(shù)家的值。同時,也要創(chuàng)建一個用于向iTunes發(fā)送請求的函數(shù)。這個函數(shù)會返回一個promise對象,當有數(shù)據(jù)從iTunes返回的時候,這個promise對象就會執(zhí)行。如果你對Angular的promise對象還不是很了解的話,推薦你去深入了解一下。

setArtist()接受一個參數(shù)并且允許用來設(shè)置藝術(shù)家的值

getArtist()返回藝術(shù)家的值

callITunes()首先會調(diào)用makeUrl()函數(shù)來創(chuàng)建我們需要使用$http進行請求的URL,然后使用我們最終的URL來發(fā)送請求,創(chuàng)建一個promise對象。由于$http返回了promise對象,我們就可以在請求之后調(diào)用.success.error了。然后我們處理從iTunes返回的數(shù)據(jù)或者駁回,并返回一個錯誤消息,比如There was an error。

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

        function makeUrl() {
            _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 () {
            var deferred = $q.defer();
            _finalUrl = makeUrl();

            $http({
                method: "JSONP",
                url: _finalUrl
            }).success(function ( data ) {
                deferred.resolve(data);
            }).error(function ( error ) {
                deferred.reject(error);
            });

            return deferred.promise;
        };

        return service;
    }]);

現(xiàn)在,我們的服務(wù)就完成了,我們可以將這個服務(wù)注入到任何的控制器了,并且,可以使用我們添加到service上的那些方法了(getArtist, setArtise, callITunes)。

app.controller("myFactoryCtrl", [
    "$scope", "MyFactory", 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 ( error ) {
                alert(error);
            });
        };
    }]);

在上面的控制器中我們注入了MyFactory服務(wù),然后,將從服務(wù)里來的數(shù)據(jù)設(shè)置到$scope的屬性上。上面的代碼中最難的地方應(yīng)該就是你從來沒有使用過promise。由于callITunes()返回了一個promise對象,所以一旦有數(shù)據(jù)從iTunes返回,promise執(zhí)行的時候,我們就可以使用.then()方法來設(shè)置$scope.data.artistData的值了。你會注意到,我們的控制器非常簡潔,我們所有的邏輯和重復(fù)性數(shù)據(jù)都寫在了服務(wù)里面。

使用service

也許在使用service創(chuàng)建服務(wù)時,我們需要知道的最重要的一件事就是他是使用new關(guān)鍵字進行實例化的。如果你是Javascript大師,你應(yīng)該知道從代碼的本質(zhì)來思考。對于那些不了解Javascript背景的或者并不熟悉new實際做了什么的程序員,我們需要復(fù)習一下Javascript的基礎(chǔ)知識,以便于最終幫助我們理解service的本質(zhì)。

為了真正的看到當我們使用new來調(diào)用函數(shù)的時候發(fā)生了什么,我們來創(chuàng)建一個函數(shù),并且使用new來調(diào)用他,然后,我們再看看在解釋器發(fā)現(xiàn)new的時候,他會做什么。最終結(jié)果肯定是一樣的。

首先創(chuàng)建我們的構(gòu)造函數(shù):

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

這是一個典型的構(gòu)造函數(shù)?,F(xiàn)在,無論我們什么時候使用new來調(diào)用這個函數(shù),this都會被綁定到新創(chuàng)建的那個對象上。

現(xiàn)在我們再在Person的原型上創(chuàng)建一個方法,以便于每一個實例都可以訪問到。

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

現(xiàn)在,由于我們在Person對象的原型上創(chuàng)建了sayName函數(shù),所以,Person的每一個實例都可以調(diào)用到這個方法。

既然我們已經(jīng)有了構(gòu)造函數(shù)和原型方法,那么,就來真正的創(chuàng)建一個Person的實例并且調(diào)用sayName函數(shù):

var tyler = new Person("Tyler", 23);
tyler.sayName();

所以,最終,所有的代碼合起來就是下面這個樣子:

function Person( 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();

現(xiàn)在我們來看看在使用new的時候到底發(fā)生了什么。首先你應(yīng)該注意到的是,在我們的例子中,使用了new之后,我們可以使用tyler來調(diào)用sayName方法,就好像這是一個對象一樣,當然,tyler確實是一個對象。所以,我們首先知道的就是無論我們是否能夠在代碼里面看見,Person構(gòu)造函數(shù)是會返回一個對象的。第二,我們我們應(yīng)該知道,sayName方法是在原型上的,不是直接定義在Person對象實例上的,所以,Person返回的對象必須是通過原型委托的。用更簡單的例子說就是,當我們調(diào)用tyler.sayName()的時候,解釋器就會說:“OK,我將會在剛創(chuàng)建的tyler對象上查找sayName函數(shù),然后調(diào)用他。等會兒,我沒有發(fā)現(xiàn)這個函數(shù),只看到了nameage屬性,讓我再檢查一下原型。哦,原來在原型上,讓我來調(diào)用他”。

下面的代碼就是你能夠想象的在Javascript里,new實際做了什么。下面的代碼是一個很基礎(chǔ)的例子,我以解釋器的視角來添加了一些注釋:

function Person( name, age ) {
    //var obj = object.create(Person.prototype);
    //this = obj;

    this.name = name;
    this.age = age;
    
    //return thisl
}

現(xiàn)在,既然知道了new做了什么,那么,使用service來創(chuàng)建服務(wù)也很容易理解了。

在使用service創(chuàng)建服務(wù)時,我們需要知道的最重要的一件事就是他是使用new關(guān)鍵字進行實例化的。與上面的例子的知識相結(jié)合,你應(yīng)該就能意識到你要把屬性和方法添加到this上,并且,服務(wù)會自動返回this。

與我們使用factory創(chuàng)建服務(wù)的方式不同,我們不需要新創(chuàng)建一個對象然后再返回這個對象,因為正如我們前面所提到的那樣,我們使用new的時候,解釋器會自動創(chuàng)建對象,并且代理到他的原型,然后代替我們返回。

所以,在所有的開始之前,我們先創(chuàng)建我們的私有輔助函數(shù),與我們之前使用factory創(chuàng)建的時候非常類似?,F(xiàn)在我不會解釋每一行的意義了,如果你有什么疑惑的話,可以看看前面的factory的例子。

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

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

現(xiàn)在,我們會把可用的方法都添加到this上。

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

        function makeUrl() {
            _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 () {
            var deferred = $q.defer();
            _finalUrl = makeUrl();

            $http({
                method: "JSONP",
                url: _finalUrl
            }).success(function ( data ) {
                deferred.resolve(data);
            }).error(function ( error ) {
                deferred.reject(error);
            });

            return deferred.promise;
        };
    }]);

現(xiàn)在,就像我們使用factory所創(chuàng)建的服務(wù)那樣,注入這個服務(wù)的任何一個控制器都可以使用setArtist,getArtistcallITunes方法了。下面是我們的myServiceCtrl,幾乎與myFactoryCtrl相同。

app.controller("myServiceCtrl", [
    "$scope", "MyService", 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 ( error ) {
                alert(error);
            });
        };
    }]);

正如我之前提到的,一旦你理解了new關(guān)鍵詞做了什么,servicefactory就幾乎是相同的。

使用provider

關(guān)于provider,要記住的最重要的一件事就是他是唯一一種可以創(chuàng)建用來注入到app.config()函數(shù)的服務(wù)的方式。

如果你需要在你的應(yīng)用在別處運行之前對你的服務(wù)對象進行一部分的配置,那么,這個就顯得很重要了。盡管與serviceprovider類似,但是我們還是會講解一些他們的不同之處。

首先,類似的,我們設(shè)置我們的provider。下面的變量就是我們的私有函數(shù)。

app.provider("MyProvider", function () {
    var baseUrl = "https://itunes.apple.com/search?term=",
        _artist = "",
        _finalUrl = "";
    
    // 從config函數(shù)里設(shè)置這個屬性
    this.thingFromConfig = "";

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

再說明一次,如果對上面的代碼邏輯有疑問的話,可以參考之前的列子。

你可以認為provider有三個部分,第一部分是私有變量和私有函數(shù),這些變量和函數(shù)會在以后被修改。第二部分是在app.config函數(shù)里可以訪問的變量和函數(shù),所以,他們可以在在其他地方使用之前被修改。注意,這些變量和函數(shù)一定要添加到this上面才行。在我們的例子中,app.config()函數(shù)能夠修改的只有thingFromConfig。第三部分是在控制器里可以訪問的變量和函數(shù)。

當使用 provider創(chuàng)建服務(wù)的時候,唯一可以讓控制器訪問的屬性和方法是在$get()函數(shù)里返回的屬性和方法。下面的代碼將$get添加到了this上面,最終這個函數(shù)會被返回。

現(xiàn)在,$get()函數(shù)會返回我們需要在控制器里訪問的函數(shù)和變量。下面是代碼例子:

this.$get = function ( $http, $q ) {
            return {
                setArtist: function ( artist ) {
                    _artist = artist;
                },
                getArtist: function () {
                    return _artist;
                },
                callITunes: function () {
                    var deferred = $q.defer();
                    _finalUrl = makeUrl();

                    $http({
                        method: "JSONP",
                        url: _finalUrl
                    }).success(function ( data ) {
                        deferred.resolve(data);
                    }).error(function ( error ) {
                        deferred.reject(error);
                    });

                    return deferred.promise;
                },
                thingOnConfig: this.thingFromConfig
            };
        };

現(xiàn)在,完整的provider就是這個樣子:

app.provider("MyProvider", [
    "$http", "$q", function ( $http, $q ) {
        var baseUrl = "https://itunes.apple.com/search?term=",
            _artist = "",
            _finalUrl = "";

        this.thingFromConfig = "";

        this.$get = function ( $http, $q ) {
            return {
                setArtist: function ( artist ) {
                    _artist = artist;
                },
                getArtist: function () {
                    return _artist;
                },
                callITunes: function () {
                    var deferred = $q.defer();
                    _finalUrl = makeUrl();

                    $http({
                        method: "JSONP",
                        url: _finalUrl
                    }).success(function ( data ) {
                        deferred.resolve(data);
                    }).error(function ( error ) {
                        deferred.reject(error);
                    });

                    return deferred.promise;
                },
                thingOnConfig: this.thingFromConfig
            };
        };

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

現(xiàn)在,與之前的servicefactory類似,只要我們把MyProvider注入到控制器里面,對應(yīng)的方法就可以使用了。下面是myProviderCtrl

app.controller("myProviderCtrl", [
    "$scope", "MyProvider", 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 ( error ) {
                alert(error);
            });
        };

        $scope.data.thingFromConfig = MyProvider.thingOnConfig;
    }]);

正如之前提到的,使用provider來創(chuàng)建服務(wù)的目的就是為了能夠通過app.config()函數(shù)修改一些變量來傳遞到最終的項目中。我們來看個例子:

app.config(["MyProviderProvider", function ( MyProviderProvider ) {
    MyProviderProvider.thingFromConfig = "This sentence was set in app.config. Providers are the only service that can be passed into app.config. Check out the code to see how it works.";
}]);

現(xiàn)在,你就能看到,在provider里,thingFromConfig是空字符串,但是,當我們在DOM里顯示的時候,他就會是我們上面所設(shè)置的字符串了。

謝謝你的閱讀,希望能夠幫助你分辨這三者的不同之處。

要查看完整的代碼例子,歡迎fork我的項目:https://github.com/tylermcginnis33/AngularServices 或者查看我在Stack Overflow的問題回答

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/78896.html

相關(guān)文章

  • AngularJS Factory、Service以及 Provider區(qū)別

    摘要:代碼代碼功夫瑜伽語法糖功夫瑜伽它是一個可注入的構(gòu)造器在中它是單例的用它在中通信或者共享數(shù)據(jù)都合適功夫瑜伽語法糖功夫瑜伽注意在里面可以不用返回東西因為會調(diào)用關(guān)鍵字來創(chuàng)建對象。 AngularJS 的供應(yīng)商($provide) $provide 服務(wù)負責告訴 AngularJS 如何創(chuàng)建一個新的可注入的東西: 即服務(wù)。 服務(wù)會被叫做供應(yīng)商的東西來定義, 可以使用 $provide 來創(chuàng)建...

    Cristic 評論0 收藏0
  • AngularJSProvider們:ServiceFactory區(qū)別

    摘要:引言看了很多文章可能還是不太說得出中的幾個創(chuàng)建供應(yīng)商的方法到底有啥區(qū)別,啥時候該用啥,之前一直傻傻分不清楚,現(xiàn)在來總結(jié)一下。 引言 看了很多文章可能還是不太說得出AngularJS中的幾個創(chuàng)建供應(yīng)商(provider)的方法(factory(),service(),provider())到底有啥區(qū)別,啥時候該用啥,之前一直傻傻分不清楚,現(xiàn)在來總結(jié)一下。 下文中泛指統(tǒng)一用中文,英文即為特...

    jone5679 評論0 收藏0
  • AngularJs 入門(二)--模塊

    摘要:同名模塊已經(jīng)初始化的模塊保存在一個叫的緩存對象中,是模塊名,是模塊對象。調(diào)用注入器的方法執(zhí)行模塊的所有方法。檢查該注入器中是否存在指定的服務(wù)。如果是數(shù)組,最后一個必須是的構(gòu)造函數(shù),前面的就是構(gòu)造函數(shù)的參數(shù)名。 模塊 模塊是指寫Angular應(yīng)用的代碼片段,這樣可以使代碼分離開來,因此代碼會更好維護,可讀和測試。還可以在module里定義代碼依賴關(guān)系,可以調(diào)用一個模塊,再在代碼中定義這個...

    Yangyang 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<