title: AngularJS cache service for in-line .svg files (wrapping $http with promises)
body: <p>I have implemented an angular <code>&lt;svgimg src="file"&gt;</code> directive to load .svg images inline, the link function uses $http to load the file which is then parsed to add and remove tags. The result is inline <code>&lt;svg&gt;</code> which can be coloured and sized with css.</p>
  
  <p>This works fine, but since my app will have <em>loads</em> of small images this solution is not very efficient because angular calls the service multiple times per digest - which means the loading/parsing process is performed 100's of times ($http cache helped).</p>
  
  <p>I am trying to replace the <code>$http.get()</code> part of the directive with a caching service.</p>
  
  <p>The cache service maintains a list of already-loaded files and provides the ready-to-inject version.</p>
  
  <p>My problem is in implementing the promises....</p>
  
  <p>The <code>app.directive()</code> link function does:</p>
  
  <pre><code>link: function( scope, element, attrs ){
      var promise= svgService.get( svgFilename );  // was: $http.get(...)
      promise.then( 
          function(data){
              // sort injected attribs and then...
              element.replaceWith(data);
          },
          function(data){ /* error stuff */ } 
      );
  };
  </code></pre>
  
  <p>which appears to be fine. </p>
  
  <p>The service function is along the lines of:</p>
  
  <pre><code>app.service('svgCacheService', ['$q', '$http', function($q, $http){
      this.get=function( srcfile ){
          var deferred= $q.defer();
  
          if( srcfile in cache is loaded ){
              deferred.resolve( cache[srcfile] );
              return deferred.promise;        // ok, no problem with this
          }else{
              if( srcfile in cache marked as 'loading' ){
                  // file is marked in cache, but is waiting for $http
                  return SOME_PROMISE;        // tried allsorts, no luck yet :(
              }else{
                  // file not in cache
                  cache[srcfile]='loading';   // new cache entry, marked 'loading' 
                  $http.get( srcfile )
                  .success( function(data){
                      // xml parsing etc. goes in here
                      cache[srcfile]= data;
  
                      // how to resolve waiting promises waiting on 'loading'???
  
                      deferred.resolve( cache[srcfile] );
                      return deferred.promise;   // this caller is ok
                  }
                  .error( ... error stuff ... )
              }
          }
      }
  </code></pre>
  
  <p>This sort-of works, but only actually loads a few images (some are used multiple times on a page and the odd one does appear) - I <em>think</em> the problem seems to be that the SOME_PROMISE's issued in the case of 'cache is loading' are not resolved.</p>
  
  <p>I have tried adding the <code>deferred</code> object in the cache and returning that to each caller, but it makes no difference.</p>
  
  <p><strong>Questions:</strong></p>
  
  <p>I'm guessing that I need to keep track of lots of separate promises... do I need to keep an array of SOME_PROMISE in the cache and then resolve them all when the $http succeeds ?</p>
  
  <p>Generally, can you only return a given promise instance to one caller ?</p>
  
  <p>Any hints/tips/links would be much appreciated... thanks.</p>