jmdobry / angular-cache

angular-cache is a very useful replacement for the Angular 1 $cacheFactory.
http://jmdobry.github.io/angular-cache
MIT License
1.39k stars 156 forks source link

IndexedDB via LocalForage ? #108

Closed noeticpenguin closed 10 years ago

noeticpenguin commented 10 years ago

Good evening,

I'm using Angular-Cache with the LocalForage library from Mozilla. I'm using the following setup for the cache:

app.config(['$angularCacheFactoryProvider',
    function($angularCacheFactoryProvider) {
        // Docs: http://jmdobry.github.io/angular-cache/configuration.html
        var localForage_wrapper = {
            assignmentCallback: function(value) {
                return value;
            },
            getItem: function(key) {
                localforage.getItem(key).then(this.assignmentCallback);
            },
            setItem: function(key, value) {
                localforage.setItem(key, value).then(this.assignmentCallback);
            },
            removeItem: function(key) {
                localforage.removeItem(key).then(this.assignmentCallback);
            }
        };
        $angularCacheFactoryProvider.setCacheDefaults({
            maxAge: 86400000,
            deleteOnExpire: 'passive',
            storageMode: 'localStorage',
            storageImpl: localForage_wrapper
            // recycleFreq: 1000,
            // cacheFlushInterval: 86400000
        });
    }
]);

Specifically using the assignmentCallback method to smooth over the async to non-async nature of the api's.

I am experiencing an issue where I seem to be experiencing severe memory leaks when large numbers of objects are injected into the indexdb cache.

I was wondering if you had any wisdom on why this might be? could it be related to the async to sync api function ? I know in the past you've declined to support indexedDB due to it's async api, does a library like local forage change your mind or offer a better way of building a cache factory for indexedDb ?

Help me obi-won, you're my only hope.

jmdobry commented 10 years ago

@noeticpenguin First off, I have zero experience with IndexedDB, so I can't provide any wisdom there. However, I am extremely skeptical of any sync-to-async conversion. It just doesn't work that way. No matter what, localforage.getItem(key) will synchronously something other than the actual value of the cached item. As far as I can tell

var localForage_wrapper = {
            assignmentCallback: function(value) {
                return value;
            },
            getItem: function(key) {
                localforage.getItem(key).then(this.assignmentCallback);
            },
            setItem: function(key, value) {
                localforage.setItem(key, value).then(this.assignmentCallback);
            },
            removeItem: function(key) {
                localforage.removeItem(key).then(this.assignmentCallback);
            }
        };

is functionally no different than

var localForage_wrapper = {
  getItem: localforage.getItem,
  setItem: localforage.setItem,
  removeItem: localforage.removeItem
};

setItem and removeItem will mostly work, in that items will be set and removed, albeit asynchronously. However, getItem will not work as expected. If you ever want Angular to use $angularCacheFactory the way it would expect to be able to $cacheFactory, this setup won't work.

I understand your use case and the functionality you're wanting to achieve, and I don't think the synchronicity of $angularCacheFactory will meet your needs.

It was for this very use case that I wrote angular-data, a data store built specifically for Angular.js. Angular-data has an asynchronous API for retrieving data from and saving data to a data source. Angular-data is made to be datasource-agnostic, using adapters to abstract away the details of communicating with different data sources. Thus far, I've only written the HTTP adapter. It looks like it would be simple to write a LocalForage adapter.

Angular-data also provides a synchronous API that you can use to query the data already in the data store. The async and sync APIs are to be used in conjunction, not interchangeably. Usually, I will make the async call for the data once, and not even worry about what it returns. Then I'll use a $scope.$watch to "watch" the data in the data store. The watch callback will be notified whenever that data in the store changes. So, when the data arrives from the async call, the watch callback will fire.

Maybe not the answer you're looking for, but I hope it's worth something.

jimthedev commented 10 years ago

@noeticpenguin Did you figure this out? I am using localForage and am thinking of implementing a cache of some sort.

noeticpenguin commented 10 years ago

No i didn’t. I’d love to see what you work out though, if you’re willing to share. --  Kevin Poorman Sent with Airmail

From: jcummins notifications@github.com Reply: jmdobry/angular-cache reply@reply.github.com Date: April 1, 2014 at 11:32:30 AM To: jmdobry/angular-cache angular-cache@noreply.github.com Cc: Kevin Poorman kjp@brightleafsoftware.com Subject:  Re: [angular-cache] IndexedDB via LocalForage ? (#108)

@noeticpenguin Did you figure this out? I am using localForage and am thinking of implementing a cache of some sort.

— Reply to this email directly or view it on GitHub.

leon commented 10 years ago

We should support that custom implementations of a cache could return a promise.

it should be as simple as whapping the get function in a $q.when().then(function (item) {...})

https://github.com/jmdobry/angular-cache/blob/v2/src/angular-cache.js#L659

This way we can support LocaleForage easily without having to resort to awaiting the promise or such.

What do you think @jmdobry?

jmdobry commented 10 years ago

@leon I think that adding asynchronicity to angular-cache will break its API compatibility with angular's $cacheFactory. According to $cacheFactory's API, get(key) is a synchronous method, and the rest of angular operates according to that premise. Unfortunately, going asynchronous/returning a promise is an unacceptable breaking change for angular-cache. That isn't to say there isn't a need for async/promises, just that they will not be addressed by angular-cache. For robust async operations, check out angular-data, for which I've already written a localforage adapter.

jmdobry commented 10 years ago

Closing in favor of js-data & js-data-localforage