【问题标题】:Limit http calls from a factory service限制来自工厂服务的 http 调用
【发布时间】:2017-05-26 02:23:06
【问题描述】:

我正在使用factory 服务来使用$http 服务获取一些数据。这里的问题是,我不想每次都发出http 请求,我想将这些数据保存在某个地方并在需要时获取它的本地副本。为此,我想在 factory 中创建一个数组,并在第一次调用时将加载的数据分配给它,然后在需要时返回它,而不是从服务器再次加载它。就我而言,http 服务每次都会被触发。我怎样才能解决这个问题?我读了here,但这并没有回答我的问题。

这是我的factory

angular.module("app").factory("getDataService", ['$http', function ($http) {
    var usersArray = [];
    if (usersArray.length === 0) {
        return {
            getJsonData: function () {
                return $http.get('https://api.myjson.com/bins/eznv3')
                    .success(function (data, status, headers, config) {
                        usersArray = data;
                        return data;
                    })
                    .error(function (error, status, headers, config) {
                    });
            }
        }
    }else{
        return usersArray;
    }
}]);

这是使用此服务的controller

angular.module("app").controller("ctrl", ["$scope", "getDataService", function ($scope, getDataService) {

    angular.element(document).ready(function () {
            getDataService.getJsonData().then(function (data) {
                $scope.users = data.data;
            });
    });
}]);

【问题讨论】:

  • @ankit 发布的内容是正确的。另一种方法是在第一次调用时将数据存储在 HTML sessionStorage 中并设置 isCacheFlag = true。在点击服务器之前,您可以检查标志是否为假,然后点击服务器,否则从 Session 或 Local storoage 提供响应
  • 谢谢补充!!顺便说一句,我们也编写了自己的代码,但是如果我们希望缓存所有 get 请求的响应,我们必须为我们发出的每个请求进行管理。但是 {cache: true} 比代码复杂性要好得多。

标签: angularjs angular-services angular-factory


【解决方案1】:

你不需要手动缓存$http.get的响应,angularJS本身提供了缓存响应的方法。在工厂的 getJsonData 函数中尝试以下代码:

getJsonData: function () {
    return $http.get('https://api.myjson.com/bins/eznv3', {cache: true})
    .success(function (data, status, headers, config) {
          return data;
     })
     .error(function (error, status, headers, config) {
     });
}

来源:https://docs.angularjs.org/api/ng/service/$http#get

阅读以上文档。您将从那里找到配置。

【讨论】:

    【解决方案2】:

    您可以使用本地存储,这是最好和最简单的方法之一。

    LocalStorage.setItem('usersArray',data); 设置本地存储中的数据。

    LocalStorage.getItem('usersArray'); 从本地存储中检索数据。

    这是你工厂的变化,

    angular.module("app").factory("getDataService", ['$http', function ($http) {
        var usersArray = LocalStorage.getItem('usersArray');
        if (usersArray.length === 0) {
            return {
                getJsonData: function () {
                    return $http.get('https://api.myjson.com/bins/eznv3', {cache: true})
                        .success(function (data, status, headers, config) {
                            usersArray = data;
                            LocalStorage.setItem('usersArray',data);
                            return data;
                        })
                        .error(function (error, status, headers, config) {
                        });
                }
            }
        }else{
            return LocalStorage.getItem('usersArray');
        }
    }]);
    

    你的控制器,

    angular.module("app").controller("ctrl", ["$scope", "getDataService", function ($scope, getDataService) {
    
        var x = [];
    
        angular.element(document).ready(function () {
            if (x.length == 0) {
                getDataService.getJsonData().then(function (data) {
                    x = data.data;
                    $scope.users = x;
                });
            }else{
                console.log("local copy of data exists");
            }
        });
    }]);
    

    本地存储的优势:

    • 借助本地存储,Web 应用程序可以在用户浏览器中本地存储数据。
    • 与 cookie 不同,存储限制要大得多(至少 5MB),而且信息永远不会传输到服务器。

    【讨论】:

    • 你不认为他需要检查本地存储是否为空。如果它为空,则进行 ajax 调用,否则从本地存储中提供数据
    • 我从未尝试过该选项,所以虽然每个人都在添加,但我没有添加,因为我不知道它是否正确。正如你所说,我现在要补充。谢谢。
    【解决方案3】:

    几天前,我有同样的需求,下面是我为同样的模块创建的代码......

    'use strict';
    (function() {
        angular.module('httpService', []).service("api", ["$http", "dbService", function($http, dbService) {
            /**
             * <Pankaj Badukale>
             * ()
             * request.url      => Url to request 
             * request.method   => request method
             * request.data     => request data
             * request.mask     => This is custom object for out use
             *
             * @return ()
             */
            return function (request) {
                var url         = (request != undefined && request.url != undefined) ? request.url : "./";
                var method      = (request != undefined && request.method != undefined) ? request.method : "GET";
                var rData       = (request != undefined && request.data != undefined) ? request.data : {};
                /**
                 * mask is CUSTOME object we add to request object
                 * Which is useful for keep track of each request as well interceptor execute
                 * 
                 * IT HAS
                 *  {
                 *      save        : true, //tell that save request response in session
                 *      fetch       : true, //check local data first,
                 *      fetchSource : tell about perticular source of data DEFAULT WILL BE sessionStorage
                 *                    OPTIONS are session and local
                 *  } strucutre FOR NOW may be it will better or enhance in future
                 *
                 * message property to set message in alert
                 * doExecute tell wheather you want to execute maskMan code for this request
                 *
                 * while saving and fetching data from local it uses URL of request as key
                 * maskMan is a factory which iterate your error response object and we can add different behaviours for maskMan
                 */
                var mask        = {};
    
                if(request != undefined && request.mask != undefined) {
                    mask = request.mask;
                }
    
                return dbService.http(request).then(function(data) {
                    console.log("Data fetched from local "+ request.url);
                    return data;
                }, function(err) {
                    return $http({
                        url: url,
                        method: method,
                        data: rData,
                        mask: mask,
                        header:{
                                'content-type':'application/json'
                        }
                    }).then(function(response) {
                        return response.data;
                    },function(error) {
                        return error;
                    });
                });
            };
        }]).service('customHttpInterceptor', ["$q", "maskMan", function($q, maskMan) {
            return {
                //before send request to server
                request: function(config) {                 
                        return config;
                },
                //if any found in request object
                requestError: function(rejection) {
                        return $q.reject(rejection);
                },
                //on response come to web app
                response: function(response) {              
                    maskMan.responseIterator(response);
                    //you to return any thing as response from here
                    return response;
                },
                //if there is error in response`
                responseError: function(rejection) {                
                    maskMan.statusIterator(rejection);              
                    return $q.reject(rejection);
                }
            };
        }]).factory("maskMan", ["dbService", function(dbService) {
            return {
                /**
                 * statusIterator
                 * Iterate response object on error comes
                 */
                statusIterator: function(rejection) {
                    if( rejection.config.mask.doExecute == true) {
                        switch(rejection.status) {
                            case 404: this.notFound(rejection);
                                break;
                            default: this.dontKnow(rejection);
                        }   
                    }
                },
                /**
                 * notFound
                 * Function to defined logic for 404 error code scenario's
                 * Here we can defined generic as well specific request object conditions also
                 */
                notFound: function(rejection) {
                    var errMsg = rejection.config.mask.message || "Something wrong";
    
                    alert(errMsg);
    
                    rejection.stopExecute = true;//stop further execute of code flag
                },
                /**
                 * dontKnow
                 * For every error response this method goingt to envoke by default
                 */
                dontKnow: function(maskObject) {
                    console.log("Don't know what to do for "+maskObject.config.url);
                },
                /**
                 * responseIterator
                 * Define logic to do after response come to browser
                 * 
                 * @params JSON resp
                 */
                responseIterator: function(resp) {
                    //Logic to save data of response in session storage with mask command save
                    if( resp.config.mask !== undefined && resp.config.mask.save === true ) {
                        var sdata   = JSON.stringify(resp.data);
                        var skey    = resp.config.url;
    
                        dbService.sinsert(skey, sdata);
                    }//END
                }
            };
        }]).service("dbService", ["$q", function($q) {
            /**
             * http
             * Custom mirror promise to handle local storage options with http
             * 
             * @params JSON request
             */
            this.http = function(request) {
                var self = this;
                return $q(function(resolve, reject) {
                    if( request.mask != undefined && request.mask.fetch === true ) {
                        var data = null;
    
                        if( request.mask.fetchSource == undefined || request.mask.fetchSource == "session") {//go for default sessionStorage
                            data = JSON.parse(self.sget(request.url));
                        } else if( request.mask.fetchSource == "local" ) {
                            data = JSON.parse(self.get(request.url));
                        } else {
                            reject( "Fetch source is not defined." );
                        }
    
                        if( data != undefined && data != null ) {
                            resolve(data);
                        } else {
                            reject("Data not saved in local "+request.url);
                        }
                    } else {
                        reject("Data not saved in local "+request.url);
                    }
                });
            }
    
            /** 
              * Add/Override data to local storage
              *
              * @params String key
              * @params Array/Json data
              * @params Function callback
              * 
              * @return Boolean/Function
              */
            this.insert =  function(key, data, callback) {          
                localStorage.setItem(key, data);
    
                if( callback != undefined ) {
                    callback();
                } else {
                    return true;
                }
            }
    
             /** 
               * Update data of local storage
               * This function generally used to data which is already exist and need to update
               * 
               * @params String key
               * @params Array/Json data
               * @params Function callback
               * 
               * @return Boolean/Function
               */
            this.update = function(key, data, callback) {
                var self = this;
                self.view(key, function(localData) {//callback function
                    if( localData != undefined && localData != null ) {
                        //already some data exist on this key So need to update it
                        data = localData.push(data);
                    }
                    //just handover to insert
                    if( callback !== undefined ) {
                        self.insert(key, data, callback);
                    } else {
                        return self.insert(key, data);
                    }
                });         
            }
    
             /**
               * Remove data from local storage on basis of key
               * 
               * @params String key
               * @return Boolean
               */
            this.remove = function(key, callback) {
                    localStorage.removeItem(key);
    
                    if( callback !== undefined ) {
                        callback();
                    } else {
                        return true;
                    }
            }
    
            /**
              * Get key data of local storage
              * @param String key
              * 
              * @return Array data WHEN all data    OR
              * @return String data WHEN key value
              */
            this.get = function(key, callback) {
                var key = key || "";
                var data = [];
    
                if( key == "" ) {
                    //get all data
                    for(var i in localStorage) {
                        data.push(JSON.parse(localStorage[i]));
                    }
                } else {
                    //get one key data
                    data = localStorage.getItem(key);
                }
    
                if(callback != undefined) {
                    callback(data);
                } else {
                    return data;
                }
            }
    
            /** 
              * sinsert
              * Add/Override data to session storage
              *
              * @params String key
              * @params Array/Json data
              * @params Function callback
              * 
              * @return Boolean/Function
              */
            this.sinsert =  function(key, data, callback) {
                var key = this.encode(key);
    
                sessionStorage.setItem(key, data);
    
                if( callback != undefined ) {
                    callback();
                } else {
                    return true;
                }
            }
    
             /** 
               * supdate
               * Update data of session storage
               * This function generally used to data which is already exist and need to update
               * 
               * @params String key
               * @params Array/Json data
               * @params Function callback
               * 
               * @return Boolean/Function
               */
            this.supdate = function(key, data, callback) {
                var self = this;
                self.view(key, function(localData) {//callback function
                    if( localData != undefined && localData != null ) {
                        //already some data exist on this key So need to update it
                        data = localData.push(data);
                    }
                    //just handover to insert
                    if( callback !== undefined ) {
                        self.insert(key, data, callback);
                    } else {
                        return self.insert(key, data);
                    }
                });         
            }
    
             /**
               * sremove
               * Remove data from session storage on basis of key
               * 
               * @params String key
               * @return Boolean
               */
            this.sremove = function(key, callback) {
                    var key = this.encode(key);
    
                    sessionStorage.removeItem(key);
    
                    if( callback !== undefined ) {
                        callback();
                    } else {
                        return true;
                    }
            }
    
            /**
              * get
              * Get key data of session storage
              * @param String key
              * 
              * @return Array data WHEN all data    OR
              * @return String data WHEN key value
              */
            this.sget = function(key, callback) {
                var key = key || "";
                var data = [];
    
                if( key == "" ) {
                    //get all data
                    for(var i in sessionStorage) {
                        data.push(JSON.parse(sessionStorage[i]));
                    }
                } else {
                    //get one key data
                    key = this.encode(key);
    
                    data = sessionStorage.getItem(key);
                }
    
                if(callback != undefined) {
                    callback(data);
                } else {
                    return data;
                }
            }
    
            /**
              * encode
              * encode give string using javascript
              *
              * @param String str
              * @return String
              */        
            this.encode = function(str) {
                return btoa(str);
            }
    
            /**
              * decode
              * decode give string using javascript
              *
              * @param String str
              * @return String
              */                
            this.decode = function(str) {
                return atob(str);
            }
    
            return this;
    
        }]).config(['$httpProvider', function($httpProvider) {
                $httpProvider.interceptors.push('customHttpInterceptor');
        }]);
    })();
    

    如何使用它::

    在你的项目中包含这个模块......

    然后对所有用于 API 调用的 http 请求始终使用“httpService”...

    我们需要将配置对象传递给该服务,告知 API 调用以及应该如何处理它......您可以在代码本身中找到有关配置的详细信息......

    那么如何在控制器中使用..

    module.controller('nameofController', ['httpService', function(httpService)  {
        httpService({
            url: 'Your API url',
            method: 'GET',
            mask: {
                      save        : true, //tell that save request response in session
                      fetch       : true, //check local data first before next fetch,
                      fetchSource : tell about perticular source of data DEFAULT WILL BE sessionStorage OPTIONS are session and local
                 }
        }).then(function(data) {
            // promise is all same as $http
            console.log(data);
        });
    }]);
    

    希望这会有所帮助...您也可以使用非常简单的解决方案来标记

    {cache: true}

    ... 但是这个解决方案是完全定制的并且在所有的控制之下

    生产中使用的原始代码在gist

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-04-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-25
      • 2022-08-18
      相关资源
      最近更新 更多