2013-05-01 12 views
7

Próbuję zrobić klasę bazową dla wszystkich moich ViewModels więc na przykład można sprawdzić „isDirty” na korzeniu-VM i go sprawdzić całą drzewo VMS (unikając wzajemnie od siebie zależnych).Odroczona ocena wszystkich obliczonych właściwości w Knockout?

Kiedy robi to zdałem sobie sprawę, że kolejność KO-właściwościach jest bardzo ważne, ponieważ nieruchomość komputerowej skonfigurować jego zapisów w oparciu o jakie inne właściwości istnieje w momencie tworzenia obiektu. Tak więc, jeśli umieściłbym obliczenie typu "tak", jak ten poniżej w klasie bazowej, to zawsze zainicjowałoby to zanim właściwości, które są zależne, nawet istnieją. W każdym razie, żeby to krótko skrócić, zauważyłem, że mogłem użyć deferEvaluation, aby zaradzić temu problemowi.

Moje pytanie to:

Czy są jakieś wady korzystania deferEvaluation wszystkich obliczonych właściwości? Dlaczego to zachowanie nie jest domyślnie prawdziwe? Kiedy powinienem go ustawić na false?

Mogę to zrobić isDirty-nieruchomość lepiej? Jakieś sugestie, jak poprawić lub zrobić to w jakiś inny sposób?

I alternatywnie, czy jest jakiś sposób, aby wyraźnie wyłączyć inicjalizacji obliczonych własności do całego obiektu jest tworzonych z wszystkimi jego właściwościami, a następnie uruchomić go w jakiś sposób. Chodzi mi o to, że jedynym problemem dla mnie jest to, że subskrypcje są ustawione zanim wszystkie właściwości są na miejscu.

Uwaga: Używam KO Lite Narzędzia do brudnej śledzenia

function ViewModel() { 
    var self = this; 
    self.isDirty = ko.computed(function() { 
     for (var p in self) { 
      if (self[p].isDirty) { 
       if (self[p].isDirty()) return true; 
      } 
      else if (self[p].subscribe && self[p].push) { // assuming ko.observableArray 
       for (var i = 0, j = self[p]().length; i < j; i++) { 
        if (self[p]()[i].isDirty) { 
         if (self[p]()[i].isDirty()) return true; 
        } 
       } 
      } 
     } 
     return false; 
    }, this, { deferEvaluation: true }); 
} 

Uwaga: Po prostu zauważyłem, że ten kod nie powiedzie się, jeśli mam inną nieruchomość komputerowej, która w zależności od isDirty. To było trochę oczekiwane, ale także niefortunne. Byłoby wspaniale, gdyby zamiast tego mogłem opóźnić i wymusić wszystkie subskrypcje po utworzeniu obiektu.

Odpowiedz

3

Jak się dowiedzieliśmy, Normalnie, ko.computed jest obliczany i zależności są wykrywane, gdy obliczona jest stworzony.

Podczas korzystania z wykrywanie zależności dla numeru ko.computed nie jest wykonywane natychmiast, ale wykonywane jest za każdym razem, gdy żądana jest wartość.

Zapewnia to potężny mechanizm dynamicznie zmieniając zależności, ale będzie to skutkować zwiększonym obciążeniu.

Ryan mówi o tym trochę on this page (przewinąć w dół do sekcji 3 - Podstawowe zasady obliczonych obserwabli):


byłoby możliwe, aby zorganizować swój kod tak, że wartości ko.computed są zdefiniowane po inne właściwości są tworzone?

Jeśli Twoim głównym problemem jest śledzenie flagi brudnej, możesz skonfigurować metody beginInit() i endInit() w swojej podstawowej maszynie wirtualnej i skonfigurować obliczoną wartość isDirty wewnątrz endInit(). Możesz lub nie potrzebujesz beginInit(), ale zapewnia on niezły haczyk dla spójności i może być przydatny później.

Oczywiście pochodna maszyna wirtualna musi wywoływać podstawowe metody inicjowania przed i po skonfigurowaniu obserwowalnych obiektów. Nie jestem pewien, jaka jest twoja obecna strategia tworzenia pochodnej maszyny wirtualnej - zwykle używam fabryki, aby zapewnić prototypowe dziedziczenie i mam taką kontrolę nad czasem inicjalizacji.

Prostszą alternatywą dla beginInit() i endInit(), jest po prostu dostarczenie funkcji initProperties() w pochodnych klasach, gdzie zdefiniowane są wszystkie właściwości i wywołanie tej metody z bazowej maszyny wirtualnej, a następnie skonfigurowanie isDirty computed.

+1

Skończyło się na użyciu metody endInit wywoływanej na końcu każdej konstrukcji klasy. Musiałem również podać jawną nazwę klasy, która wywołuje endInit, tak że tylko klasa "najwyżej" łańcucha dziedziczenia faktycznie wykonuje endInit. To nie jest idealne, ale działa. –

2

Jeśli Twoja computed jest rzeczywiście obliczeniem, to generalnie nie szkodzi odraczanie oceny, dopóki ktoś nie będzie potrzebował tej wartości.

W przypadkach, gdy Twoje computed faktycznie wykonuje pewną akcję jako produkt uboczny uzyskania wartości lub jako jej jedyny cel, wówczas odroczenie oceny może nie być właściwym wyborem. W niektórych przypadkach można użyć metody computed do subskrybowania wielu obserwowalnych obiektów i wykonania akcji, gdy któraś z nich ulegnie zmianie, a nie po prostu zwraca wartość.

Nie ma sposobu wyłączenia inicjowania, dopóki cały obiekt nie zostanie utworzony inaczej niż przez odłożenie oceny i uzyskanie dostępu do niej później, chyba że ma się coś takiego jak utworzenie obliczonego w postaci setTimeout. Może to jednak powodować błędy, jeśli inny kod tego oczekuje.

+0

masz konkretny przykład, kiedy potrzebuję "sposobu na subskrybowanie wielu obserwowalnych elementów i wykonania działania, gdy którykolwiek z nich zmieni się, a nie po prostu zwróci wartość". Mam sporo "wyliczonych", które dają dość skomplikowane obliczone wartości, ale nie jestem świadomy żadnego z nich, który mógłby się zepsuć, gdyby odroczony był prawdziwy. Zastanawiam się nad pomocnikiem w stworzeniu defered = true obliczonym, ale nie chcę bez pełnego zrozumienia sytuacji, w której byłoby źle –

+1

@Simon_Weaver - byłby to przypadek, w którym obliczane jest po prostu reagować na zmiany do jednego lub więcej obserwowalnych zamiast zwracania wartości. Na przykład, możesz utworzyć komputer, który uzyskuje dostęp do wszystkich obiektów obserwowanych w obiekcie ('ko.toJS (this)' zrobiłoby lewę) i wywołuje pewien typ zapisu do bazy danych, gdy jakiekolwiek zmiany. Tak więc, obliczony byłby prosty sposób, aby to osiągnąć, a próba stworzenia ręcznego subskrypcji przeciwko każdemu obserwowanemu w hierarchii obiektu. –

+0

ok tak zasadniczo mówisz, że już wiedziałem, że robię to ;-) Myślę, że nadal nie w pełni rozumiem, dlaczego "odroczone = prawda" nie jest domyślne. Przypuszczam, że miło jest uderzyć w każdy odroczony obiekt po skonstruowaniu obiektu, aby natychmiast ujawnić jakiekolwiek błędy, ale czasami natrafiam na przypadki, w których chcę je wszystkie zignorować (jak robi to mapująca wtyczka podczas mapowania obiektu) –

Powiązane problemy