Johan
Johan

Reputation: 35213

Determine if observable has changed in computed

I am implementing a cache function in a computed observable.

Is there any way to invalidate the cache below if the items collection differs since the last call?

I have seen examples of dirty checking where a serialized version of the observable is used to determine if the collection has changed, but it's too expensive for me, since there may be hundreds of items.

var itemCache;

var manipulatedItems = ko.pureComputed(function(){
    var items = someObervable();
    if(!itemCache /* || someObervable.hasChangedSinceLastCall */) {
        itemCache = heavyWork(items);
    }
    return itemCache;
});

var heavyWork = function(items){
    // do some heavy computing with items 
    return alteredItems;
};

In my viewmodel:

myViewModel.itemList = ko.pureComputed(function(){
    var result = manipulatedItems();
    return result;
});

Upvotes: 1

Views: 1017

Answers (2)

Michael Best
Michael Best

Reputation: 16688

Since computed observables always cache the last value, there's no reason to store it separately. In fact, storing it separately can cause trouble with getting the latest data in your application.

var manipulatedItems = ko.pureComputed(function () {
    var items = someObervable();
    return heavyWork(items);
});

var heavyWork = function (items) {
    // do some heavy computing with items 
    return alteredItems;
};

Upvotes: 2

Jeroen
Jeroen

Reputation: 63830

Yes, but you need to use .subscribe and keep the relevant moments in vars inside your own closure. There is no "last-modified-moment" property on observables or inside ko utils to be found.

In your repro, you could do something like this:

var lastChange = new Date();
var lastCacheRebuild = null;
var itemCache;

someObervable.subscribe(function(newObsValue) { lastChange = new Date(); });

var manipulatedItems = ko.pureComputed(function(){
    var items = someObervable();
    if(!itemCache || !lastCacheRebuild || lastChange > lastCacheRebuild) {
        lastCacheRebuild = new Date();
        itemCache = heavyWork(items);
    }
    return itemCache;
});

As far as the repro is concerned you could even put the items = someObservable() bit inside the if block.

PS. This is not recursive, i.e. the subscription is only on someObservable itself, not on the observable properties of things inside that observable. You'd have to manually craft that, which is specific to the structure of someObservable.

Upvotes: 0

Related Questions