【问题标题】:KnockoutJS: Spurious callback with large count of observablesKnockoutJS:具有大量可观察对象的虚假回调
【发布时间】:2012-09-16 14:24:00
【问题描述】:

我有一个使用 KnockoutJS 的页面,其中包含大量的 observables(这里大约有 35 个相关,总共大约 60 个)。我用的是KO映射插件,不知道是不是跟我的问题有关。

大多数(不是全部)可观察对象都绑定到输入字段。

用户可以将当前输入集保存到命名集,或从以前保存的集重新加载。有 UI 可指示当前输入集是来自已保存的集,还是已编辑(未保存)的输入。

为了在编辑任何输入时更新“保存/加载输入”UI(我不在乎哪一个),我订阅了所有相关的“输入”可观察对象。

这是我的奇怪问题:当订阅的 observables 的数量大约为 25 或更高时,我从 ko.applyBindings(...) 调用的深处收到了对回调函数的虚假调用。

  • 当它发生时,只有一个虚假回调
  • 报告的输入通常是我订阅的最后一个。
  • 如果我删除了足够多的订阅,以至于我订阅了大约 25 个或更少,虚假回调就会消失。
  • 如果我通过了该限制并继续添加订阅,则调用会在我不断添加到列表中时重新出现在不同的字段中。
  • 如果我订阅了所有输入,那么回调声称是 __ko_mapping__ 的回调,这很荒谬。

我必须假设我没有正确绑定到订阅,或者 KO 或 KO 映射插件中存在导致订阅列表混乱的错误。到目前为止,我无法跟踪问题。

订阅代码大致如下:

// markSavedInputsDirty(name) defined elsewhere
function registerCallbacks() {
    var data = viewModel.inputs;
    var member;
    for(member in data) {
        if (data.hasOwnProperty(member) && ko.isObservable(data[member])) {
            if(member /* ... not certain observables which I need to ignore */ ) {
                data[member].subscribe(function() {return markSavedInputsDirty(member)}, data[member]);
            }
        }
    }
}

(注意:上面的代码跟踪调用了哪个成员,但仅作为调试帮助。当我们最初看到问题出现时,代码过去只是对所有可观察对象使用相同的回调函数(没有柯里化) )

以前有人见过这样的吗?

【问题讨论】:

  • 在您的回调函数中,member 将不准确。我知道你之前说过你有这个问题,但是如果你想实际调试它,你应该确保它是正确的。为此,您需要将其保存在每个订阅的新闭包中。类似function(member){data[member].subscribe(...)}(member)
  • @MichaelBest,你是对的。关闭被搞砸了,这让我误入歧途。我将用决议简要更新帖子。谢谢!
  • 我很高兴你明白了。您最好添加一个答案并将其标记为已接受,这样它就不会一直保留为“未回答”。我也很感激我的评论+1。 :-)
  • 我想我两天不能接受自己的答案。我会回来标记它。再次感谢。

标签: knockout.js knockout-mapping-plugin knockout-2.0


【解决方案1】:

解决方案:

subscribe(...) 调用的关闭被搞砸了,正如@MichaelBest 在 cmets 中指出的那样。我虽然它会在调用点包含member 的值,但它包含member 本身(对象,所有调用都相同)。我看到的是循环中member 的最终值,这让我误入歧途。我不应该在午夜这样做。

这是该行的正确实现:

data[member].subscribe(markSavedInputsDirty.bind(data[member], member));

一旦我进行了正确的诊断,一切都变得清晰起来:虚假调用来自页面中 <select> 元素上的 value 绑定。 Knockout 内部需要确保选定的<option> 的值与viewModel 的值完全相同(请参阅Knockout 源中的ensureDropdownSelectionIsConsistentWithModelValue(...))。

在我的例子中,可观察值有 3(数字),而选定的 <option>——自然——有“3”(字符串)。因此,Knockout 将 viewModel 设置为选项的值,并触发了通知。

因此,最初的订阅(在我失败的柯里化尝试之前)是正确的,并且通知是合法的。我只需要交换一些东西,这样我的监控代码在绑定之前不会有任何影响。

【讨论】:

    猜你喜欢
    • 2012-04-20
    • 2012-12-12
    • 2017-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-13
    相关资源
    最近更新 更多