2015-10-05 10 views
6

$ http経由でリソースを返すためのやや複雑なメソッドを構築しました。

方法は、約束を返し、その後リソースがまだ存在する場合は、私のローカルキャッシュをチェックします。そうであれば、キャッシュされたリソースを返します。そうでなければ、$ http要求を行います。これは、リソースがキャッシュされた後にうまくいくが、私はロード時にこのメソッドを打つアプリケーションを介して複数の関数があり、リソースが返されてキャッシュされていないので、それらのすべてがhttp要求を行う。

私はこれを修正する簡単なチェックを思い付いたのが、より良い方法があるはずような気がします。メソッドがリソースを取得する途中にある場合はtrueに設定されたブール値を追加し、半分のタイムアウトでメソッドを解決した場合は、要求の解決に時間を要します。コードは以下のとおりです。

だから、もっと良い方法がありますか?

var schools = []; 
    var loadingSchools = false; 

    function getAllSchools(forceUpdate) { 
     return $q(function (resolve, reject) { 
      if(loadingSchools) resolve($timeout(getAllSchools, 500)); 

      else{ 

       loadingSchools = true; 

       if (schools.length && !forceUpdate) { 
        loadingSchools = false; 
        resolve(schools); 
        return; 
       } 

       console.log('$http: Getting All Schools - schoolService.js'); 

       $http.get(API_PATH + 'schools_GetAll', {cache:true}) 
       .success(function(result) { 
        schools = result; 
        loadingSchools = false; 
        resolve(schools); 
       }) 
       .error(function(error) { 
        schools = []; 
        loadingSchools = false; 
        reject(error); 
       }); 
      } 
     }); 
    } 
+1

は、元の約束は、あなたが解決返したときに多分あなたはその関数への登録タイムアウトを設定する基本的にはなく、あなたがして待機約束を管理関数を作成しています – Saar

+2

を登録したすべてのものは、特に 'ui-router'を使用している場合には、ルータで解決策を使用する方がはるかに簡単です。どのルータを使用していますか? – charlietfl

+0

@Saar - 良い考え方、私はそのようなことをすることを検討していましたが、この投稿を最初にしたいと思っていました。私はこれを行う方法が$ httpに組み込まれていると考えました。 – Kolby

答えて

20

まず、HttpPromiseを別の約束事にする必要はありません。 success/error方法deprecatedで、あなたは単にthen()方法に頼る必要があり、普通の約束としてHttpPromiseを扱います。

要求が1回だけ送信されるようにするには、作成した最初のHttpPromiseを実際に追跡し、その後の関数呼び出しで同じ約束を返します。ここで

は、引数としてAPIエンドポイントを受け入れ、そして唯一の要求はそのAPIに送信されることを保証するサービスです。

app.factory('$httpOnce', [ '$http', '$cacheFactory', 
    function ($http, $cacheFactory) { 
    var cache = $cacheFactory('$httpOnce'); 

    return function $httpOnce(url, options) { 
     return cache.get(url) || cache.put(url, $http.get(url, options) 
     .then(function (response) { 
      return response.data; 
     })); 
    }; 
    } 
]); 

使用

function log(data) { 
    console.log(data); 
} 

// issues an HTTP request 
$httpOnce('https://api.github.com/').then(log); 
// does not issue an HTTP request, returns the same promise as above 
$httpOnce('https://api.github.com/').then(log); 

// ... 
// HTTP request completes somewhere, both promises above are resolved 
// ... 

setTimeout(function() { 
    // immediately resolved 
    $httpOnce('https://api.github.com/').then(log); 
}, 5000); 

ここdemoです。開発ツールでは、リクエストが1つしか発行されていないことがわかります。

+0

まさに私が探していたものです。答えをありがとう。 – Kolby

+0

私はこの解決策に関して質問がありますが、なぜそれがうまく機能するかを理解したいと思います。 あなたは$ http.getキャッシュに結果を置くとき、あなたも)キャッシュに追加する前に、(そう$ http.get(URL、オプション)は約束を返し、あなたがそれを使用する)約束を実行します。なぜあなたは別のものを使うことができますか?その後、キャッシュを取得すると()? 'cache.get'から返される約束はありません。 $ http.getは1つの約束を返し、結果を返します - 別の約束を返しますか同じですか? ありがとうございました。私に詳細をお伝えするための参考資料があれば教えてください。 – florinmtsc

+0

確かに 'cache:true'フラグは同じことをしますか?何か不足していますか? – zilj

0

Iここだけ正確に同じ問題とは私のサービス

app = angular.module('MM_Graph') 

class Team_Data 
    constructor: ($routeParams,$rootScope, $cacheFactory, $q, API)-> 
    @.$routeParams = $routeParams 
    @.$rootScope = $rootScope 
    @.$cacheFactory = $cacheFactory 
    @.cache   = $cacheFactory('team_Data') 
    @.$q   = $q 
    @.deferred  = null 
    @.API   = API 
    @.project  = null 
    @.data   = null 
    @.team   = null 
    @.schema  = null 


    call_With_Cache: (method, params, callback)=>         # method that uses promises to prevent multiple parallel calls 

    cache_Key = "#{method}_#{JSON.stringify(params)}"       # create cache key using method and params 

    if not @.cache.get cache_Key            # if this is the first require for this type of data (method_project_team) 
     deferred = @.$q.defer()             # create a new instance of deferred 
     @.cache.put cache_Key, deferred.promise         # put its promise in the cache 

     on_Data_Received = (data)->            # simple callback method to resolve the promise 
     deferred.resolve(data)             # resolve promise (this is the data that will show as the 1st param in 'then') 

     method_Params = params.concat(on_Data_Received)       # append on_Data_Received callback method to the current 'method' params list 

     @.API[method].apply(null, method_Params)         # invoke 'method' in @.API 

    @.cache.get(cache_Key).then (data)->          # invoke the 'then' from the promise (will happen async until data is recevied) 
     callback (data)               # finally call the original callback with the data received from 'method' 

    clear_Data:()=> 
    @.cache.removeAll() 
    @.scores = null 
    @.schema = null 
    @.data  = null 
    @.deferred = null 

    load_Data: (callback)=> 
    if not (@.$routeParams.project and @.$routeParams.team)      # check that project and team are set 
     return callback() 

    if (@.$routeParams.project is @.project and @.$routeParams.team is @.team) # check if either the project or team have changed 
     # do nothing here since project or team have not changed 
    else 
     @.clear_Data()               # when project changes remove all cache entries 
     @.project = @.$routeParams.project 
     @.team = @.$routeParams.team 
     @.project_Schema (schema)=>            # get projecg schema 
     @.data_Score (scores)=>             # get current team scores 
      @.team_Get (data)=>             # get team data 
      @.scores = scores 
      @.schema = schema 
      @.data = data 

      @.deferred.resolve()            # trigger promise resolve 

    @.deferred ?= @.$q.defer()             # ensure @.deferred object exits 
    @.deferred.promise.then ->             # schedule execution 
     callback()                # invoke original caller callback 

    data_Score : (   callback) => @.call_With_Cache 'data_Score'  , [@.project, @.team  ], callback 
    project_Schema: (   callback) => @.call_With_Cache 'project_Schema' , [@.project    ], callback 
    radar_Fields : (   callback) => @.call_With_Cache 'data_Radar_Fields', [@.project    ], callback 
    radar_Team : (target_Team, callback) => @.call_With_Cache 'data_Radar_Team' , [@.project, target_Team ], callback 
    team_Get  : (   callback) => @.call_With_Cache 'team_Get'   , [@.project, @.team  ], callback 

    save: (callback)=> 
    @.API.file_Save @.project, @.team , @.data, callback 

app.service 'team_Data', ($routeParams, $rootScope, $cacheFactory, $q, API)=> 
    return new Team_Data $routeParams, $rootScope, $cacheFactory, $q, API 
関連する問題