2016-08-09 27 views
1

Ich implementiere eine Cache-Funktion in einer berechneten Observable.Bestimmen, ob Observable hat sich in berechnet geändert

Gibt es eine Möglichkeit, den Cache unten ungültig zu machen, wenn die items Sammlung seit dem letzten Aufruf abweicht?

Ich habe Beispiele von Dirty Checking gesehen, wo eine serialisierte Version der Observable verwendet wird, um festzustellen, ob die Sammlung geändert wurde, aber es ist zu teuer für mich, da es Hunderte von Elementen geben kann.

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 meinem Viewmodel:

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

Was versuchen Sie zu tun, die Sie noch nicht haben? Observables werden zwischengespeichert. Wenn sich 'someObservable' nicht geändert hat, gibt 'manipulatedItems' nur den zwischengespeicherten Wert zurück; Es wird nicht jedes Mal neu ausgeführt, wenn Sie seinen Wert erhalten. Wenn sich 'someObservable' ändert, aktualisiert Knockout den zwischengespeicherten Wert. –

+0

@RoyJ Ah, mir war nicht bewusst, dass es nicht jedes Mal neu ausgeführt wurde. Problem gelöst durch Knockout dann denke ich :) Danke! – Johan

+0

Beachten Sie, dass das Festlegen von 'someObservable' möglicherweise immer noch mehr Neubewertungen auslöst, als Sie möchten. Wenn es sich zum Beispiel um ein beobachtbares Array handelt, möchten Sie sicherstellen, dass Sie keine Objekte einzeln nacheinander anschieben. Sie könnten Ihrem 'pureComputed' ein' console.log' hinzufügen, wenn Sie ein Gefühl dafür bekommen möchten, wie oft der Wert ausgewertet wird. – user3297291

Antwort

2

Da die berechneten Observablen immer den letzten Wert zwischenspeichern, gibt es keinen Grund, sie getrennt zu speichern. In der Tat kann das separate Speichern Probleme beim Abrufen der neuesten Daten in Ihrer Anwendung verursachen.

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

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

Ja, aber Sie müssen in Ihrem eigenen Verschluss .subscribe und halten die entsprechenden Momente in Vars verwenden. Es gibt keine "Last-Modified-Moment" Eigenschaft auf Observablen oder innerhalb von Ko-Utils zu finden.

In Ihrem repro, könnten Sie so etwas tun:

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; 
}); 

Was die Repro Sie sogar die items = someObservable() Bit innerhalb des if Block setzen könnte betroffen ist.

PS. Dies ist nicht rekursiv, d.h. das Abonnement ist nur auf someObservable selbst, nicht auf die beobachtbaren Eigenschaften der Dinge innerhalb, die beobachtbar. Sie müssten das manuell erstellen, was für die Struktur von someObservable spezifisch ist.

+0

Würde nicht 'lastChange> lastCacheRebuild' immer als 'true' ausgewertet, da die 'lastChange = new Date()' Subskription immer _just_ vor der Subskription erfolgt, die in 'pureComputed' erstellt wurde? Änderungen an 'someObservable' lösen immer die Auswertung beider Funktionen aus, nein? – user3297291

+0

@ user3297291 Hmm, du hast recht, zumindest in einigen Punkten. Ich mache lieber eine echte Repro, um das zu demonstrieren, also kann ich auch die Implementierungsdetails reparieren. Könnte ein bisschen dauern, bevor ich dazu komme. In der Zwischenzeit werde ich diese Antwort verlassen, weil die Grundidee dieser Antwort intakt bleiben würde: "Verwenden Sie ein Abonnement". – Jeroen