在 knockout.js 中更改 observable 但不通知订阅者

Posted

技术标签:

【中文标题】在 knockout.js 中更改 observable 但不通知订阅者【英文标题】:Change observable but don't notify subscribers in knockout.js 【发布时间】:2013-08-01 17:31:50 【问题描述】:

有没有办法在可观察的值变化时忽略订阅者。我想更改 observable 的值,但不使用 knockout.js 为订阅者执行它

【问题讨论】:

正如 RP 所指出的,这通常不是一个好主意。你的用例是什么?是否有您不想通知的特定订阅者? 我想在这种情况下你需要改变你的逻辑,因为淘汰赛并不意味着像这样工作。 【参考方案1】:

通常这是不可能的或不可取的,因为它可能会使依赖链中的事物不同步。使用限制扩展器通常是限制依赖项接收的通知数量的好方法。

但是,如果您真的想这样做,那么一种选择是覆盖 observable 上的 notifySubscribers 函数并让它检查标志。

这是一个将这个功能添加到 observable 的扩展:

ko.observable.fn.withPausing = function() 
    this.notifySubscribers = function() 
       if (!this.pauseNotifications) 
          ko.subscribable.fn.notifySubscribers.apply(this, arguments);
       
    ;

    this.sneakyUpdate = function(newValue) 
        this.pauseNotifications = true;
        this(newValue);
        this.pauseNotifications = false;
    ;

    return this;
;

你可以把它添加到一个像这样的 observable 中:

this.name = ko.observable("Bob").withPausing();

然后您可以通过以下方式在不通知的情况下更新它:

this.name.sneakyUpdate("Ted");

【讨论】:

+1 用于节流。在设置计算所依赖的多个可观察对象时,我想避免多次运行计算。结果:速度++ 在这种情况下,暂停通知是最合适的,这样您就可以更新所有可观察对象并仅在最后触发订阅(ryan 的帖子knockmeout.net/2011/04/pausing-notifications-in-knockoutjs.html 不错的答案。我认为 'sneakyUpdate' 最好命名为 'poke',因为 KO 提供了一个内置的 'peek' 方法,它确实很容易阅读。 'poke' 将是 'peek' 的可写版本。 有一个用例,我从 ajax 下拉选项并将下拉值 3 设置为默认选择和第一个,当用户更改选项值时我想要一些逻辑,如何这样做。 请问,我怎样才能在 TypeScript 中做同样的事情?使用上面的代码,它向我显示“TS2339:'ObservableFunctions' 类型上不存在属性'withPausing'。”【参考方案2】:

更简单的方法:

ko.observable.fn.silentUpdate = function(value) 
    this.notifySubscribers = function() ;
    this(value);
    this.notifySubscribers = function() 
        ko.subscribable.fn.notifySubscribers.apply(this, arguments);
    ;
;

如下使用:

this.status = ko.observable("Happily Married");
this.walkIntoBar();
this.status.silentUpdate("Single");
this.walkOutOfBar(); // careful with exceptions
this.status.silentUpdate("Happily Married");

谨慎使用。我们正在处理一个可观察的对象,因此如果您未能通知您的订阅者,可能会发生不好的事情。

【讨论】:

加一个或创意示例! 请问,我怎样才能在 TypeScript 中做同样的事情?上面的代码显示“TS2339:属性‘silentUpdate’在类型‘ObservableFunctions’上不存在。” 嗨@bondif,我对打字稿不太熟悉抱歉,您似乎无法覆盖方法,这确实是打字稿的重点(即在构建时检查强类型)但我确定有一些方法可以绕过它。【参考方案3】:

我喜欢 @RP Niemeyer 在需要忽略所有订阅者时提供的解决方案。但是,就我而言,我在 Select 控件上有一个带有 2 路绑定的 observable。使用 @RP Niemeyer 时,Select 控件不会更新。所以,我真的需要一种方法来关闭特定的观察者,而不是全部。这是针对这种情况的通用解决方案。

为“安静”订阅和“安静”写入添加扩展方法。

ko.observable.fn.ignorePokeSubscribe = function (callback, thisValue, event)
    var self = this;
    this.subscribe(function(newValue) 
        if (!self.paused)
            callback(newValue);
    , thisValue, event);
    return this;
;
ko.observable.fn.poke = function (newValue) 
    this.paused = true;
    var result = this(newValue);
    this.paused = undefined;
    return result;
;

你会订阅 observable 像:

this.name = ko.observable("Bob");
this.name.ignorePokeSubscribe(function(newValue)  /* handler */ ));

然后您可以通过以下方式在没有特定通知的情况下更新它:

this.name.poke("Ted");   // standard subscribers still get notified

【讨论】:

我认为这并不像您认为的那样。 感谢@Barry Franklin,我将拼写修正为“安静” 谢谢,v 能够抑制代码更改通知很有用,正是我所需要的 :) 有一点需要注意,我怀疑如果 observable 有速率限制,这将不起作用,因为在清除暂停后回调将触发。此外,如果订阅返回订阅以便您可以处理它(如标准订阅方法)会很好 RP Niemeyer 的回答很好,但这是我的确切用例:我希望 UI 仍然更新,但阻止特定的网络通道,因为为了提高效率,大量通信了一系列更改。 【参考方案4】:

我提出这个问题是因为我正在构建一个分页数据网格。只显示了 10 行,每行都有一个复选框。表头有一个(取消)全选复选框。

在负载测试期间,我们发现单击全选复选框会导致一次更新 1000 个可观察对象。这花费的时间太长了。

看起来 KO 更新了 html 1000 次,尽管只有 10 个 observables 绑定到 HTML。

如果有人出于同样的原因发现此问题,我建议您查看延迟更新。延迟更新队列通知订阅者,它会在您的“线程”完成后通知您的订阅者。延迟更新可以为每个 observable 或整个应用程序配置。

http://knockoutjs.com/documentation/deferred-updates.html

【讨论】:

以上是关于在 knockout.js 中更改 observable 但不通知订阅者的主要内容,如果未能解决你的问题,请参考以下文章

Knockout JS,如何在更改可观察数组中的值时更改样式属性

有条件地在 knockout.js 中添加元素属性

选择了 Knockout.js 下拉绑定

Knockout.js ko.mapping.toJS 在我看来没有刷新数据

Knockout js表编辑列获取onkeyup / Onchange最新值。 [小提琴](https://jsfiddle.net/chiks/975ncawv/521/)

Knockout JS映射插件没有初始数据/空表单