在knockout.js 中更改可观察但不通知订阅者

IT技术 javascript events knockout.js
2021-02-19 07:43:41

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

4个回答

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

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

这是一个将此功能添加到 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");
在这种情况下,最合适的方法是暂停通知,以便您可以更新所有的 observables 并且仅在最后触发订阅(ryan 的postknockmeout.net/2011/04/pausing-notifications-in-knockoutjs.html
2021-04-18 07:43:41
请问,我如何在 TypeScript 中做同样的事情?使用上面的代码,它向我显示“TS2339:'ObservableFunctions<any>' 类型上不存在属性 'withPausing'。”
2021-04-23 07:43:41
有一个用例,我从 ajax 中拉出下拉选项,并将下拉值 3 设置为默认选择和第一个,当用户更改选项值时,我想要一些逻辑,如何做到这一点。
2021-04-28 07:43:41
+1 用于节流。在设置计算所依赖的多个 observable 时,我想避免多次运行计算。结果:速度++
2021-04-30 07:43:41
很好的答案。我认为 'sneakyUpdate' 可以更好地命名为 'poke',因为 KO 提供了一个内置的 'peek' 方法,它可以很好地读取。“poke”将是“peek”的可写版本。
2021-05-14 07:43:41

一个更简单的方法:

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");

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

嗨@bondif,我对typescript不太熟悉,抱歉,您似乎无法覆盖方法,这确实是typescript的重点(即在构建时检查强类型),但我确定有一些方法可以解决它.
2021-04-19 07:43:41
加一还是创意例子!
2021-04-21 07:43:41
请问,我如何在 TypeScript 中做同样的事情?使用上面的代码,它向我显示“TS2339:'ObservableFunctions<any>' 类型上不存在属性 'silentUpdate'。”
2021-05-04 07:43:41

当需要忽略所有订阅者时,我喜欢@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
RP Niemeyer 的回答很好,但这是我的确切用例:我希望 UI 仍然更新,但阻止特定的网络通道,因为为了提高效率而批量传达了一系列更改。
2021-04-19 07:43:41
我不认为这意味着你认为它意味着什么。
2021-04-21 07:43:41
谢谢,v 能够抑制代码更改的通知很有用,正是我需要的 :)
2021-04-23 07:43:41
谢谢@Barry Franklin,我将拼写固定为“安静”
2021-05-06 07:43:41
需要注意的一件事是,我怀疑如果 observable 有速率限制,这将不起作用,因为在清除暂停后回调将触发。此外,如果订阅返回订阅以便您可以处理它会很好(就像标准订阅方法一样)
2021-05-09 07:43:41

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

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

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

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

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