Pure computed observables 纯计算监控属性
纯计算监控属性在knockout3.2.0中引入,给在大多数场合下常规的计算监控属性提供了一个速度和内存性能更好选择。这是因为纯计算监控属性在它本身没有被订阅的情况下不需要维护它的依赖。
它的特性:
Prevents memore leaks 防止内存泄露。纯计算监控属性不再是一个程序引用,但是它的整个依赖依然存在。
Reduces computation oberhead 减少计算开销。当值不再被监控时不再进行计算监控属性的计算。
纯计算监控属性基于其是否包含更新订阅自动的切换两种状态:
1. 当其不再被订阅时,它将处于休眠状态(sleeping)。当进入休眠状态,它扔掉所有的依赖订阅,在这种状态下,它不会订阅计算函数中的任何监控依赖(尽管仍然保持对它们的跟踪)。如果计算监控属性的值在睡眠状态下被读取,它将在任意一个依赖变化的情况下自动的重新计算。
2. 每当有任何订阅改变,它将被激活并且进入监听状态(listening)。当进入监听状态时,它将立即订阅任何依赖,在这种状态下,它的操作就像一个普通的计算监控属性,如同上一节( how dependency tracking works )中描述的那样。
Why “pure”?
我们从纯函数pure functions中借鉴了这一概念,这个特性一般只适用于有纯计算函数的计算监控属性:
1. 评估计算该计算监控属性不应引起副作用;
2. 计算监控属性的值不应该随多个计算函数或其他隐藏的信息而变化,它的值应该仅依赖其它单一的监控属性。
Syntax 语法
定义纯计算监控属性的标准方法是使用ko.pureComputed:
this.fullName = ko.pureComputed(function() { return this.firstName() + "" + this.lastName(); }, this);
作为选项,你也可以在ko.computed中使用pure选项:
this.fullName = ko.computed(function() { return this.firstName() + " " + this.lastName(); }, this, { pure: true });
参考完整的语法,可以参照 computed observalbe reference.
When touser a pure computed observable 什么时候使用纯计算监控属性
你可以参考纯函数指导(pure function guidelines)使用纯计算监控属性。在应用程序需要设计解决在模板视图和视图模型之中使用并共享视图模型时非常有用。使用纯计算监控属性在持久化视图模型时提供了高性能的计算方式,在模板视图中提供了高效的内存管理方式。
在下边的一个简单向导的例子中, fullName 纯计算监控属性只在最后一步被绑定到视图上并且只会在这一步被激活时才会更新。
<div class="log" data-bind="text: computedLog"></div> <!--ko if: step() == 0--> <p>First name: <input data-bind="textInput: firstName" /></p> <!--/ko--> <!--ko if: step() == 1--> <p>Last name: <input data-bind="textInput: lastName" /></p> <!--/ko--> <!--ko if: step() == 2--> <div>Prefix: <select data-bind="value: prefix, options: ['Mr.', 'Ms.','Mrs.','Dr.']"></select></div> <h2>Hello, <span data-bind="text: fullName"> </span>!</h2> <!--/ko--> <p><button type="button" data-bind="click: next">Next</button></p> function AppData() { this.firstName = ko.observable('John'); this.lastName = ko.observable('Burns'); this.prefix = ko.observable('Dr.'); this.computedLog = ko.observable('Log: '); this.fullName = ko.pureComputed(function () { var value = this.prefix() + " " + this.firstName() + " " + this.lastName(); // Normally, you should avoid writing to observables within a pure computed // observable (avoiding side effects). But this example is meant to demonstrate // its internal workings, and writing a log is a good way to do so. this.computedLog(this.computedLog.peek() + value + '; '); return value; }, this); this.step = ko.observable(0); this.next = function () { this.step(this.step() === 2 ? 0 : this.step()+1); }; }; ko.applyBindings(new AppData());
When not to use a pure computed observable 什么时候不适合使用纯计算监控属性
Side effects 副作用
你不应该以在他的依赖改变时执行动作的方式使用计算监控属性,参看以下的例子:
使用有多个依赖的计算监控属性来调用回调函数;
ko.computed(function () { var vleanData = ko.toJS(this); myDataClient.update(cleanData); }, this);
绑定 init 函数,使用计算监控属性来更新绑定的元素
ko.computed({ read: funtion() { element.title = ko.unwrap(valueAccessor()); }, disposeWhenNodeIsRemoved: element });
你不应该使用纯计算监控属性的原因是如果计算函数有重要的作用那么它并不会再订阅未被激活时调用(例如sleeping状态时)。如果你需要在依赖变化时总是能得到计算函数的响应,你应该使用常规的计算监控属性。
Determining if a property is a pure computed observable 检测一个属性是纯计算监控属性
在一些场景下,你可能需要检测处理的是否是一个计算监控属性,knockout提供一个工具函数, ko.isPureComputed 来实现这一目的。例如,你想要在发送到服务端的数据中排除掉非纯计算监控属性的数据。
var result = {}; ko.utils.objectForEach(myObject, function(name, value) { if (!ko.isComputed(value) || ko.isPureComputed(value)) { result[name] = value; } });
State-change notifications 状态改变通知
纯计算监控属性会在其进入监听状态(listening)时触发 awake 事件(使用它当前的值), 在进入休眠状态(sleeping)时触发 asleep 事件。内部状态可以对应检测到而不论计算监控属性是否绑定到视图,因此你可以使用这些信息在视图模型初始化或者清除时做一些事情
this.someComputedThatWillBeBound = ko.pureComputed(funtion () { ... }, this); this.someComputedThatWillBeBound.subscribe(funtion () { // do somethig when this is bound }, this, "awake"); this.someComputedThatWillBeBound.subscribe(function() { // dom somethig when this is un-bound }, this, "asleep");
(awake 事件同样也在常规计算监控属性中提供了,使用 deferEvaluation 选项创建)