之前有個錯誤認知,想像Knockout會在ko.computed宣告時期分析其與哪些obersvable相依,藉此訂閱變更事件,實現相依observable變動後立即重算的能力。在範例20時踢到鐵板! 情境是ko.computed因if條件式在某些情況下不會讀取observable,沒想到此後該obersvable的變動便不再觸發重算。這才驚覺,原來的想法錯得離譜!!

JavaScript是直譯式語言,未經事先編譯,一定要實際執行過才知函數邏輯,怎麼會出現"宣告時期如何如何"的情境? (謎之聲: 連這都錯,出來打手心) 更進一步,由觀察結果發現: 每次執行computed後,Knockout會重新定義其相依關係,這次沒讀取到的observable,就失去了相依關係,下回該observable變動時將不再觸發重算。

我們設計一個實驗來驗證這個行為:

<!DOCTYPE html>
 
<html>
<head>
    <title>相依追蹤實驗</title>
    <script src="../Scripts/jquery-1.7.2.js"></script>
    <script src="../Scripts/knockout-2.1.0.debug.js"></script>
    <script>
        $.ajaxSettings.cache = false;
        function MyViewModel() {
            var self = this;
            self.text1 = ko.observable("Jeffrey");
            self.text2 = ko.observable("Darkthread");
            self.textPlus = ko.observable();
            self.textSharp = ko.observable();
            self.recalcTime = ko.observable(new Date().getTime());
            ko.computed(function () {
                self.recalcTime(new Date().getTime());
                self.textPlus(self.text1() + "+");
                if (self.text1() != "Disable") {
                    self.textSharp(self.text2() + "#");
                }
            });
        }
        $(function () {
            ko.applyBindings(new MyViewModel());
        });
    </script>
    <style>
        body, input
        {
            font-size: 9pt;
        }
        .disp
        {
            background-color: #C0C0C0;
        }
    </style>
</head>
<body>
    <input type="text" data-bind="value: text1" style="width: 80px;"/>
    <input type="text" data-bind="value: textPlus" class="disp" readonly /><br />
    <input type="text" data-bind="value: text2" style="width: 80px;"/>
    <input type="text" data-bind="value: textSharp" class="disp" readonly /><br />
    <span data-bind="text: recalcTime"></span>
    <br />
</body>
</html>

網頁上有兩個可輸入的<input>,分別繫結到text1及text2兩個observable,其後分別跟著兩個唯讀<input>,分別繫結到textPlus及textSharp兩個observable。定義了一個computed,將text1加上"+"號寫入textPlus,將text2加上"#"號寫入textSharp,但有個特別條款,若text1() == "Disable",便不更新textSharp。為了明確掌握重算發生時機,再定義一個recalcTime屬性,每次computed執行時填入new Date().getTime(),由數字變化藉以確認computed是否被呼叫執行。

 
線上展示

一開始,不論修改text1或text2,textPlus及textSharp都會立即連動。接著我們在text1填入"Disable",便可發現之後再修改text2,textSharp都不會變更,但這有可能是if (text1() == "Disable")不成立造成的,所以我們需要由下方的數字判定: 當text1=="Disable"時,修改text2便不會引發下方數字改變,證明了KO已不再判定computed與text2相依!

接著,我們將text1改回非"Disable",textSharp馬上更新,之後修改text2也會觸發下方數字跳動,驗證KO已再次認定computed與text2相依。

由此實驗得知,KO會在每次computed執行後重新定義相依關係! 在設計一些進階computed應用時,可留意此原則。


Comments

Be the first to post a comment

Post a comment