【问题标题】:Knockout computed triggering multiple times on a single actionKnockout 计算在单个操作上多次触发
【发布时间】:2014-03-11 08:05:40
【问题描述】:

我正在使用但未构建的软件遇到淘汰问题。当几乎任何字段被编辑时,相关页面都会执行自动保存。该页面显示多个测试问题,每个测试问题都有相关的响应(答案)。自动保存是使用脏标志实现的,该标志将对象的当前状态与初始状态进行比较。

我看到的症状是,当第一次访问该页面并添加一个新问题时,会导致对 1 个新问题进行 1 次 API 调用(这是正确的)。如果我导航到另一个页面并返回相同的测试(或不同的测试),所有 api 调用都会重复。如果我再次重复同样的事情,则会进行 3 次调用(完全相同)。我的理论是离开页面时 VM/observable 中的某些内容没有正确取消设置。我已经对此进行了很多调试,我认为没有多个不同的操作触发保存,但是有一个操作导致触发计算函数,每次打开任何测试时都会触发自动保存。刷新浏览器会导致这个不可见的计数器重置。

有两个计算函数

self.dirtyQuestions = ko.computed(function() {
  return ko.utils.arrayFilter(self.current.assessmentItems(), function(question) {
    return question.dirtyFlag.isDirty();
  });
}, self).extend({ throttle: 250 });

self.triggerDirtyQuestionSave = ko.computed(function() {
  if (!CONFIG.editing.autoSave) {
    return;
  }
  if (self.dirtyQuestions().length > 0) {
    self.saveQuestions(self.dirtyQuestions(), true);
  }
}, self);

这似乎完全依赖于一个可观察的数组

  assessmentItems: ko.observableArray([]),

这是一个有许多与之关联的可观察对象的对象。如果其中任何一个被修改或推送了新项目,则会在上述两个计算中触发自动保存。在调试时,我看到这些都在离开并重新访问页面后被多次触发,但是我所有对assessmentItems observable 中元素的修改的断点只会触发一次。

我的具体问题是,如何确定页面/VM/observablearray 的某些内容在离开页面后是否会持续存在,从而在离开和返回可能解释这些重复触发器的页面时导致累积?该页面有点乱,但也相当复杂,所以我试图避免重新编写它或去掉所有的自动保存功能。

--更新

路由表条目

        create: {
      enter: [
        checkForUnsavedChanges,
        function () {
          self.closeOverlay();
      }],
      to: function() {
        assessmentAuthoringVM = new AssessmentAuthoringVM(self);
      },
      exit: function() {
        if (assessmentAuthoringVM) {
          assessmentAuthoringVM.destroy();
        }
      }
    },

【问题讨论】:

  • 如果通过离开页面,您的浏览器实际上会导航到不同的页面(与 SPA 相对),那么客户端上没有任何内容会被保留(除了本地存储 - 您是否在使用它?有吗?)。页面中的任何内容都不会保留。现在,持久化的是任何被推送到服务器,然后被取回的东西。也许看看你的数据请求?
  • 您是否检查过是否所有的事件处理程序都被解除挂钩?在没有看到更多代码的情况下,您似乎有挥之不去的事件处理程序。检查处理程序或处理程序被触发的次数是否在增加。如果这个数字在增加,那就是问题所在。
  • @voithos:该应用程序是一个 SPA,很抱歉未将其包含在原始描述中。 @ Eric:我确实检查了此处描述的dependencyCount(ko.computedContext.getDependenciesCount():knockoutjs.com/documentation/computedObservables.html),并且真的希望它每次都会上升,但它没有。是否有一个我可以查看的较低级别的事件处理程序实际上不会复制数据? (即,当新项目被推入 observablearray 时,发生双触发时永远不会有 2 个被推入)。谢谢大家的回复。
  • @LukeRice:如果没有更多信息,我们很难确定问题所在。您的网站是面向公众的吗?如果没有,您认为应用程序的其他部分是否相关?另外,这里有一个随机猜测:每次导航到页面时,页面是否都会重新运行视图模型初始化函数?如果是这样,那么它可能正在重新创建视图模型的多个实例并将其绑定到 DOM,这将解释复合 API 调用。
  • @LukeRice:不幸的是,路由表代码并没有说太多,除了在退出时它试图破坏绑定。 quick test 表明,如果您尝试重新绑定两次,Knockout(我相信 2.3 及更高版本)将引发错误。所以,在这一点上,我想说只是尝试在代码周围放置一些console.logs,看看随着时间的推移视图模型会发生什么。

标签: javascript knockout.js


【解决方案1】:

在“页面”关闭时运行的函数中,您应该添加调用以“处理”计算的 observable:

destroy: function () {
    self.triggerDirtyQuestionSave.dispose();
    self.dirtyQuestions.dispose();
}

【讨论】:

  • 我会尝试一下,我昨天开车回家时也有同样的想法,但我还没有尝试过。谢谢
  • 这真是太棒了。我之前曾尝试(手动)处理它们,但我意识到存在一个复杂的错误,即如果我在导航离开之前单击页面中的某些内容,实际上并没有调用 destroy 方法。在此过程中,我遇到了 2 或 3 个复杂的错误/无效的 hacky 修复,这使得诊断变得非常痛苦。谢谢老兄。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-05
  • 2015-04-06
  • 2017-07-11
  • 2013-07-26
  • 1970-01-01
  • 2018-09-11
相关资源
最近更新 更多