KO 3.2版險了美妙的HTML自訂元素,還有一項小革新 - pureComputed。
依據官方文件,pureComputed 的 pure 借用自 Pure Function,其主要設計理念在於:
- 計算 computed observable 時不應產生任何副作用。
- computed observable 結果不因估算次數或其他「隱藏」資訊而不同,只與其他 observable 值相關,對應到 Pure Function,其他 observable 的值相當於輸入參數。
這定義聽起來好學術,但用起來沒這麼複雜。簡單來說,pureComputed 有兩種狀態,Sleeping 與 Listening,在未被訂閱時(訂閱來源可能是其他 computed、pureComputed 或是 data-bind="" 宣告…等等),pureComputed 將停止重算,即便其所依賴的 obervable 改變,也不會重新計算結果。但是當它再被其他來源訂閱追蹤時,其表現就跟一般 computed 完全相同。
pureComputed 最大的好處在於能節省非必要的反覆計算,例如在大型 SPA(Single Page Applcation)中,在某些 UI 不顯示時,其相關 ViewModel 的 computed 並不需持續更新,此時便是使用 preComputed 的好時機。
用一個例子來展示:
在以上程式中,有一個每秒減少1的倒數值 observable(靠 setInterval 驅動),Countdown(n) 及 Computed(p) 分別用 data-bind="text: …" 繫結到 computed 及 pureComputed 寫成的函式取得文字。每次 computed 及 pureComputed 重算時,會在下方 textarea 寫 Log 方便觀察執行次數。最上方的按鈕可以切換 data-bind 繫結的元素出現與否(這裡用 if切換而非 visible,因為 visible 隱藏時元素仍存在DOM之中,會繼續訂閱 preComputed)。
由實驗結果可以發現,當元素被隱藏,computed 仍會持續重算,但 preComputed 因無人訂閱進入 Sleeping 狀態,不再因 setInterval 改變倒數值重算;當元素恢復顯示,訂閱生效,preComputed 進入 Listening 狀態,也恢復定期重算。
完整程式碼如下:Live Demo
<!DOCTYPEhtml>
<html>
<head>
<metacharset="utf-8">
<title>KO PureComputed</title>
<style>
</style>
</head>
<body>
<inputtype="button"value="Toggle Panel"data-bind="click: toggle"/>
<divdata-bind="if: showPanel">
<divdata-bind="text: countdownDispN"></div>
<divdata-bind="text: countdownDispP"></div>
</div>
<textareaid="logger"style="width: 480px; height: 200px;">
</textarea>
<scriptsrc="http://knockoutjs.com/downloads/knockout-3.2.0.js"></script>
<script>
var logger = document.getElementById("logger");
function log(msg) {
logger.value += ", " + msg;
}
function myViewModel() {
var self = this;
self.countdown = ko.observable(256);
self.showPanel = ko.observable(true);
self.toggle = function() {
self.showPanel(!self.showPanel());
};
self.countdownDispN = ko.computed(function() {
log("computed");
return"Countdown(n)=" + self.countdown();
});
self.countdownDispP = ko.pureComputed(function() {
log("pureComputed")
return"Countdown(p)=" + self.countdown();
});
}
var vm = new myViewModel();
setInterval(function() {
vm.countdown(vm.countdown() - 1);
}, 1000);
ko.applyBindings(vm);
</script>
</body>
</html>
最後補充一點:pureCompouted 在每次由 Sleeping 切換到 Listening 時也會重算,而 computed 只有在相依 observable 變化時才重算,若遇到頻繁切換 Sleeping / Listening 狀態的情境,使用 pureComputed 的效能反而不如 computed。
[KO系列]