【问题标题】:Prevent computed from collecting dependencies防止计算收集依赖项
【发布时间】:2013-01-14 06:14:54
【问题描述】:

有没有好办法大致实现如下概念:

var computed = ko.computed(function() {
    readSomeObservables(); //<-- if these change, notify computed
    ko.stopCollectingDependencies();
    readSomeMoreObservables(); //<-- if these change, do not notify computed
    ko.resumeCollectingDependencies();
});

我知道peek(),但在这种情况下,计算是调用从外部模块提供的方法,如果这些方法碰巧涉及可观察对象,设计要求它纯粹是偶然的。

我有一个解决办法,大致是这样的:

window.setTimeout(function() {
    readSomeMoreObservables();
}, 0);

但由于显而易见的原因,这并不理想,并且在某些情况下会导致不良行为。

【问题讨论】:

  • 如果你不希望它在这些变化时更新,你为什么要从计算中读取它们?
  • 我将重申问题中所说的内容:情况相当复杂,因为外部模块可以提供需要在特定点调用的额外回调执行流程,但如果这些回调碰巧涉及从 observables 读取,那么这些 observables 不应该参与计算。所以我可以重新设计整个模块(昂贵)或找到解决方法(便宜)。
  • 所以当那些改变时计算不需要发布给它的订阅者?对吗?
  • @Anders close - 计算对象首先不应该订阅那些 observables;因为它不能重新评估自己的读取功能,更不用说通知它的订阅者了。
  • 您不能让 readSomeMoreObservables 背后的团队将其扩展为使用 peek 或标准读取?

标签: knockout.js computed-observable


【解决方案1】:

为以后的访问者...

3.3 版公开了 ko.ignoreDependencies(callback, callbackTarget, callbackArgs)。这是绑定处理程序处理在内部使用的方法,以避免从 init 函数调用创建依赖关系。

http://www.knockmeout.net/2015/02/knockout-3-3-released.html

【讨论】:

  • 相比.peek()函数有什么优势?
  • OP 折扣 peek()。我认为是因为 peek() 只忽略了最初的 observable,而 ignoreDependencies 创建了一个围绕回调的新范围。
【解决方案2】:

我有点晚了,但这是我在这种情况下使用的解决方案:

var computed = ko.computed(function() {
    var a = readSomeObservables(); //<-- if these change, notify computed
    var b;

    // capture any dependencies from readSomeMoreObservables
    // in a temporary computed, then immediately dispose
    // of it to release those captured dependencies
    ko.computed(function() { b = readSomeMoreObservables(); }).dispose();

    return a + b; // or whatever
});

这会创建一个临时计算,我们称之为readSomeMoreObservables。临时计算设置了一个新的依赖捕获帧,因此所有读取的可观察数据都被捕获到我们的临时计算中。然后我们立即处理临时计算以释放它捕获的任何依赖项。

【讨论】:

    【解决方案3】:

    组合怎么样。为您需要阅读但不想订阅的可订阅内容创建一个临时计算。更改它们会更新计算的温度,但这可能是一个便宜的操作。您的实际计算读取 tempComputed 并 peek 访问当前缓存的值。

    // this one is updated 
    // if any of the subscribeables used in readSomeMoreObservables changes
    // but that is hopefully cheap
    var tempComputed = ko.computed(function() {
        readSomeMoreObservables();
    });
    
    
    var computed = ko.computed(function() {
        readSomeObservables(); //<-- if these change, notify computed
    
        // do not update on readSomeMoreObservables
        tempComputed.peek(); 
    });
    

    【讨论】:

    • 好主意,我用我的回答中的小提琴测试了这一点,jsfiddle.net/uUXWv/3
    • 糟糕,在我完全了解此解决方案的含义之前发表了评论。这是一个非常好的主意 - 我添加了 deferEvaluation 以确保调用顺序保持不变:jsbin.com/etuxuq/1 谢谢!
    • 这是个好主意,但对于后来的访问者,@RockResolve 提供了更现代的解决方案below
    【解决方案4】:

    Knockout 的依赖检测有一个ko.dependencyDetection.ignore 函数。如果我理解正确,您可以使用它来读取可订阅的值,而无需创建对它们的依赖。

    至少运行以下测试:

    it('Should not subscribe to subscribeables called by ignore', function() {
    
    
        var observableInner = ko.observable('initial'),
            observableOuter = ko.observable(),
            called = 0,
            computedInner = ko.computed(function() { return observableInner(); }),
            computedOuter = ko.computed(function() { 
                called += 1;
                // read dependend
                observableOuter();
    
                // read ignored
                var result = ko.dependencyDetection.ignore(computedInner, null)
                expect(result).toEqual('initial');
    
                return true;
            });
    
        expect(called).toEqual(1);
    
        // update the one we are depending on
        observableOuter(1);
        expect(called).toEqual(2);        
    
        // update the inner one which should trigger an update to computedInner but not to computedOuter
        observableInner('ignore');
        expect(called).toEqual(2);
    });
    

    【讨论】:

    • ko.dependencyDetection 是一个内部辅助函数
    • 哦,我错过了那个。您可以创建自己的“自己构建”的淘汰赛导出该属性: ko.exportSymbol('dependencyDetection', ko.dependencyDetection);
    【解决方案5】:

    如果您对这些可观察对象的新值不感兴趣,为什么不将可观察对象的读数移到计算范围之外?

    http://jsfiddle.net/uUXWv/2

    var observableTwoInitialState = this.observableTwo(); 
    
    this.computed = ko.computed(function() {
        return this.observableOne() + observableTwoInitialState;
    }, this);
    

    【讨论】:

    • 我的小提琴在更新可观察到的两个时有一个错误尝试最新的一个
    • 这并没有解决问题,因为我无法控制真实场景中的所有代码。
    • ko 不支持这个开箱即用,你需要使用 peek 并且因为你不能改变函数 readSomeMoreObservables 这会很困难。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-15
    • 2011-11-27
    • 2016-02-05
    • 1970-01-01
    • 2013-04-30
    • 2011-08-04
    • 2019-02-07
    相关资源
    最近更新 更多