KO範例32-pureComputed
2 | 11,257 |
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
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>KO PureComputed</title>
<style>
</style>
</head>
<body>
<input type="button" value="Toggle Panel" data-bind="click: toggle"/>
<div data-bind="if: showPanel">
<div data-bind="text: countdownDispN"></div>
<div data-bind="text: countdownDispP"></div>
</div>
<textarea id="logger" style="width: 480px; height: 200px;">
</textarea>
<script src="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系列]
Comments
# by LaLaLiLaLa
不知道黑暗大有沒有用過knockoutmvc? http://knockoutmvc.com/ 個人認為最大的好處應該是比較有結構, intelliSense和執行時期debug較方便(ASP.Net MVC)
# by Jeffrey
to LaLaLiLaLa, 有試過,但近年來工作漸以SPA專案為主,多靠HTML+JS運作,很少寫cshtml,故使用經驗不多。