【问题标题】:How to call function only once when multiple subscribed variables are called together多个订阅变量一起调用时如何只调用一次函数
【发布时间】:2017-03-06 23:49:51
【问题描述】:

这不是一个专门的技术问题,但我很好奇解决此类问题的最佳方法是什么?虽然我在 Knockout 中遇到了这个问题,但我确信该用例在其他地方也有效。

假设我订阅了 2 个变量,simpleObserve1simpleObserve2,因此每次它们的值发生变化时,它们都会调用一个函数 resetAllValues()

var simpleObserve1 = ko.observable(0), // initial values
    simpleObserve2 = ko.observable(0); // initial values

var resetAllValues = function resetAllValues() {
    /* this function takes all observable values and resets them */
    {...}
}

simpleObserve1.subscribe(function(){
    resetAllValues();
});

simpleObserve2.subscribe(function(){
    resetAllValues();
});

simpleObserve1(5); // value changed anywhere in code
simpleObserve2(10); // value changed anywhere in code

这里有 2 个问题。

  1. 当resetAllValues()被调用时,它会将所有订阅的值变为0,包括simpleObserve1simpleObserve2。这反过来又一遍又一遍地调用resetAllValues()。如何防止它进入无限循环?
  2. 如果我想同时更新两个变量,但只调用一次resetAllValues(),该怎么办?

我尝试使用knockout's dispose() 方法来帮助我,但我想知道是否有更好的方法来做到这一点。

【问题讨论】:

    标签: javascript knockout.js observer-pattern observable


    【解决方案1】:

    Deferred Updates 可能会帮助你。通过在计算中使用 observables 的值,敲除创建订阅。通过扩展这个计算,快速成功的变化被组合到某种微任务中。

    它们阻止了循环行为,但仍不清楚触发了多少更新。即:当设置为 510 导致 12 计算更新。所以我不完全确定这是否能回答你的问题。

    var i = 0,
      simpleObserve1 = ko.observable(0), // initial values
      simpleObserve2 = ko.observable(0); // initial values
    
    ko.computed(function resetAllValues() {
      console.log("Set " + ++i + ", before:");
      console.log("1: ", simpleObserve1());
      console.log("2: ", simpleObserve2());
    
      simpleObserve1(0);
      simpleObserve2(0);
    
      console.log("Set " + i + ", after:");
      console.log("1: ", simpleObserve1());
      console.log("2: ", simpleObserve2());
    
    }).extend({
      deferred: true
    });
    
    simpleObserve1(5); // value changed anywhere in code
    simpleObserve2(10); // value changed anywhere in code
    .as-console-wrapper { min-height: 100%; }
      
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

    【讨论】:

      【解决方案2】:

      我创建了一个高阶函数acceptXParams,它将检查参数的数量是否等于fn.length 或任意数字。如果不是,则不会调用原始函数:

      function acceptXParams(fn, numOfParams) {
        var numOfParams = numOfParams === undefined ? fn.length : numOfParams;
        
        return function() {
          if(arguments.length !== numOfParams) {
            return; 
          }
          
          return fn.apply(fn, arguments);
        }
      }
      
      /** example **/
      
      function sum(a, b, c) {
        return a + b + c;
      }
      
      var sum3 = acceptXParams(sum);
      
      console.log(sum3(1, 2, 3));
      
      console.log(sum3(1, 2));
      
      console.log(sum3(1, 2, 3, 4));

      还有一个更时尚的 ES6 版本acceptXParams

      const acceptXParams = (fn, numOfParams = fn.length) => 
          (...args) => 
              args.length === numOfParams ? fn(...args) : undefined;
      

      【讨论】:

        猜你喜欢
        • 2012-12-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-14
        • 1970-01-01
        • 1970-01-01
        • 2015-10-26
        • 1970-01-01
        相关资源
        最近更新 更多