4.纯计算属性

纯计算监控在KO 3.2.0中开始引入,比大多数应用程序使计算监控有更大的性能提升和内存优化。这是因为在自身没有订阅的时候不会保持订阅状态。特性如下

  • 阻止内存泄露 - 避免在应用程序里计算监控不再被引用但是依赖仍然存在。
  • 减少计算开销 - 当值不再被监控不会重新计算计算监控的值。

纯计算监控会在两个状态之间自动切换,基于它是否改变了订阅者。

  1. 当订阅者没有发生改变,它会休眠。当进入休眠状态,它释放所有自身依赖的订阅。在这种状态下,它不会订阅访问求值函数里面的的监控对象(尽管它会继续跟踪它们)。在休眠的时候计算监控的值被读取,如果依赖对象有发生改变,它会自动重新求值。
  2. 当订阅者发生任何改变。它会苏醒并开始监听。处于监听状态,它会马上订阅所有依赖。在这种状态下,它就像计算监控一样工作。

什么是"纯"函数?

(该概念属于函数式编程)

我们参考了pure函数的术语,因为这个特性仅可以应用与计算监控,求值程序的纯功能描述如下 :

  1. 对计算监控求值不会引起任何其他影响。
  2. 计算监控的值不应该受求值规模或其他隐藏信息导致变化。它的值应该仅仅受程序里面其他监控对象的值导致变化,对于纯函数的定义,都考虑了它的参数

语法

定义一个纯计算监控的标准方法是使用ko.purecomputed

this.fullName = ko.pureComputed(function() {
return this.firstName() + " " + this.lastName();
}, this);

或者你可以使用ko.computedpure选项:

this.fullName = ko.computed(function() {
return this.firstName() + " " + this.lastName();
}, this, { pure: true });

1. 什么情况下使用纯计算监控

你可以在任何计算监控上使用pure特性。你会看到大部分的好处,尽管当它被应用到应用程序设计时,会使用到持久视图模型和共享临时视图和视图模型。在持久视图模型下使用纯计算监控会提供更好的计算性能。在临时视图模型下使用纯计算监控会提供更好的内存管理。

在下面这个简单的导航界面的例子中,纯计算监控属性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();
//通常情况下,你应该避免在一个纯计算监控里面对一个监控对象赋值(避免副作用)。但是这个例子是为了说明其内部工作原理,输出日志是一种很好的说明方式
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());

2. 什么情况下使用纯计算监控

副作用

在依赖项发生改变的时候需要执行一个操作的时候不应该使用计算监控的pure特性。如例子所示:

  • 基于多个监控的一个计算监控执行一个回调函数
ko.computed(function () {
var cleanData = ko.toJS(this);
myDataClient.update(cleanData);
}, this);
  • 在绑定的初始化函数,使用计算监控更新绑定元素值。
ko.computed({
read: function () {
element.title = ko.unwrap(valueAccessor());
},
disposeWhenNodeIsRemoved: element
});

你不应该使用纯计算监控的原因是如果求值函数很容易引起严重的副作用,副作用就是无论何时计算未激活订阅(也就是休眠状态),求值函数就不会执行。当依赖改变,求值函数就必须执行,请使用计算监控。

3. 确定一个属性是否上纯计算监控

在某些场景,如果你用纯计算监控处理问题,通过程序确定某个属性是否是纯计算监控是很有用的。KO提供了一个工具函数,ko.isPureComputed能处理这个问题。比如,您可能希望从返回服务器的数据中排除非纯计算监控值。

var result = {};
ko.utils.objectForEach(myObject, function (name, value) {
if (!ko.isComputed(value) || ko.isPureComputed(value)) {
result[name] = value;
}
});

4. 状态改变通知

当纯计算监控进入监听状态,它会通知awake事件(使用其当前值),当它进入睡眠状态,它会通知一个asleep事件(使用undefined值)。一般情况下,你不需要知道计算监控内部的状态。但是内部状态可以反应出计算监控是否绑定到了视图,你可能会利用那个状态信息做一些视图模型初始化或清理。

this.someComputedThatWillBeBound = ko.pureComputed(function () {
...
}, this); this.someComputedThatWillBeBound.subscribe(function () {
// do something when this is bound
}, this, "awake"); this.someComputedThatWillBeBound.subscribe(function () {
// do something when this is un-bound
}, this, "asleep");

awake事件在一般的计算监控用deferEvaluation选项创建的时候也会响应。

Knockout v3.4.0 中文版教程-8-计算监控-纯计算属性的更多相关文章

  1. Knockout v3.4.0 中文版教程-5-计算监控-使用计算监控

    3. 计算监控 1.使用计算监控 如果你有一个监控的属性firstName和另一个lastName,但你想显示全名怎么办? 这就是引入计算监控的原因-这是依赖于一个或多个其他的observables函 ...

  2. Knockout v3.4.0 中文版教程-9-计算监控-API参考

    5.参考 下面的内容描述了如何构建和使用计算监控. 1. 构建一个计算监控 可以用如下的形式构建一个计算监控: ko.computed( evaluator [, targetObject, opti ...

  3. Knockout v3.4.0 中文版教程-6-计算监控-可写的计算监控

    2.可写的计算监控 初学者可能想要跳过本节 - 可写的计算监控是相当高级的部分,在大多数情况下不是必需的. 通常,计算监控是一个通过其他监控值计算出的值,因此是只读的. 令人惊讶的是,可以使计算监控值 ...

  4. Knockout v3.4.0 中文版教程-7-计算监控-依赖跟踪如何工作

    3.依赖跟踪如何工作 初学者不需要知道这一点,但更高级的开发人员将想知道为我们怎么实现KO自动跟踪依赖性和自动更新UI的正确部分... 它其实相当简单优雅,跟踪算法如下: 当你定义一个计算监控,KO立 ...

  5. Knockout v3.4.0 中文版教程-4-通过监控数组工作

    2.通过监控数组工作 1. 监控数组 如果你想检测或者响应一个对象的改变,你用observables.如果你想检测和响应一个集合的改变,使用observableArray.这个在很多情况下都非常有用, ...

  6. Knockout v3.4.0 中文版教程-16-控制流-foreach绑定

    2. 控制流 1. foreach绑定 目的 foreach绑定会遍历一个数组,为每个数组项生成重复的元素标记结构并做关联.这在渲染列表或表格的时候特别有用. 假设你的数组是一个监控数组,之后无论你进 ...

  7. Knockout v3.4.0 中文版教程-1-入门和安装

    英文原版教程:http://knockoutjs.com/documentation/introduction.html 注:此教程根据英文原版翻译,仅作练习,如有不足或错误,请指正 说明: 对原文中 ...

  8. Knockout v3.4.0 中文版教程-11-控制文本内容和外观-text绑定

    2. text绑定 目的 text绑定把传入的参数通过关联的DOM元素来显示文本值. 通常这对像<span>或<em>标签等使用,但技术上你可以对任何元素使用该绑定. 例子 T ...

  9. Knockout v3.4.0 中文版教程-14-控制文本内容和外观-style绑定

    5. style绑定 目的 style绑定用来给关联的DOM元素添加或移除一个或多个样式值.在如下情况很有用,比如,当某些值为负时,高亮显示,或者设置容器元素的宽度来匹配数值的改变. (注意:如果你不 ...

随机推荐

  1. python学习之图形界面编程:

    一 tkinter:tkinter是python自带的支持tk的库,python代码调用tkinter->tk->操作系统提供的本地GUI(TKL语言开发))完成界面开发,不需要安装任何第 ...

  2. (转)Unity3D中常用的数据结构总结与分析

    http://www.cnblogs.com/murongxiaopifu/p/4161648.html#array   1.几种常见的数据结构 常碰到的几种数据结构:Array,ArrayList, ...

  3. (wp8.1开发)触摸键从推出变返回

    ---恢复内容开始--- 今天开发wp8.1,遇到这样一个问题,从第一个页面跳到第二个页面,在第二个页面按返回,结果程序退出了.原来是系统把返回键定义成退出了. 解决办法: 在第一个页面加入如下代码 ...

  4. codeforces736D. Permutations(线性代数)

    题意 $m \leqslant 500000$,题目打错了 Sol 神仙题Orz 构造矩阵$B$,使得$B[b[i]][a[i]] = 1$ 那么他的行列式的奇偶性也就对应了生成排列数列数量的奇偶性( ...

  5. 前端上传插件Plupload的实际使用(个人实操)

    一个主要的页面,其中包裹了一个iframe页面,在项目中,这个iframe页面包裹在主页面的div标签中,主要用于上传文件附件. 用的是plupload.full插件,主要引入以下几个js: jque ...

  6. mysql命令行执行时不输出列名(字段名)

    -N 即可 如:mysql -N -e "select * from test" 摘自:http://blog.csdn.net/eroswang/article/details/ ...

  7. ios UI自动化测试

    转载:http://www.cnblogs.com/dokaygang128/p/3517674.html 一.一些注意事项: 1.做自动化测试时注意如果是真机话首先要设置不锁屏. 2.自动化测试过程 ...

  8. jQuery备忘录

    jquery 中遍历数组 var arr = [1,2,3,4,5] $.each(arr,function(i,j){ console.log(i,j) }) 结果 0 1 1 2 .... jQu ...

  9. Prim算法解决最小生成树

    一.最小生成树问题 什么是最小生成树问题?给你一个带权连通图,需要你删去一些边,使它成为一颗权值最小的树. 二.Prim算法 1)输入:输入一个带权连通图,顶点集合V,边集合E 2)初始化:Vnew= ...

  10. Spring框架context的注解管理方法之二 使用注解注入基本类型和对象属性 注解annotation和配置文件混合使用(半注解)

    首先还是xml的配置文件 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns=" ...