如何从节流函数中获取最后一个值

How to get last value from throttled function

本文关键字:获取 最后一个 函数      更新时间:2023-09-26

_.strottle函数的文档指出:

创建一个节流函数,该函数在每等待毫秒。节流功能带有取消功能方法取消延迟的func调用,并使用flush方法立即调用它们。提供一个选项对象以指示应在等待的前沿和/或后沿调用func超时。使用提供给的最后一个参数调用func节流功能。对节流函数的后续调用返回最后一次函数调用的结果

我对这条线感兴趣:

对节流函数的后续调用返回最后一次函数调用的结果

我试过:

var throttled = _.throttle(updateModelData, 1000);
service.on('change', function () {
    throttled(5);
});
function updateModelData(data) {
    // all calls here log 5's
    console.log(data);
    return data;
}
setTimeout(function() {
    throttled(); // here updateModelData is executed with `undefined` value
}, 5000);

问题是throttled()在不返回数据的情况下触发函数。我如何调用它以使它返回最后的数据?

编辑:

根据源代码,只有当不存在挂起的函数调用isCalled === false:时,才会返回该值

  function debounced() {
    args = arguments;
    stamp = now();
    thisArg = this;
    trailingCall = trailing && (timeoutId || !leading);
    if (maxWait === false) {
      var leadingCall = leading && !timeoutId;
    } else {
      if (!maxTimeoutId && !leading) {
        lastCalled = stamp;
      }
      var remaining = maxWait - (stamp - lastCalled),
          isCalled = remaining <= 0 || remaining > maxWait;
      !!!!! HERE
      if (isCalled) {
        if (maxTimeoutId) {
          maxTimeoutId = clearTimeout(maxTimeoutId);
        }
        lastCalled = stamp;
        result = func.apply(thisArg, args);
      }
      else if (!maxTimeoutId) {
        maxTimeoutId = setTimeout(maxDelayed, remaining);
      }
    }
    ...
    return result;
  }

因此,以下操作将起作用:

var throttled = _.throttle(updateModelData, 10000);
service.on('change', function () {
    throttled(5);
});
function updateModelData(data) {
    // all calls here log 5's
    console.log(data);
    return data;
}
setTimeout(function() {
    throttled(); // returns 5
}, 15000);

问题是,当您有前导调用(_.throttle的默认行为)时,当您第一次调用节流函数(或在延迟时间过后第一次调用它)时,它会立即调用底层函数,然后再返回任何内容。

这意味着"上一次函数调用的结果"可能是由您当前对节流函数的调用所引起的函数调用结果。因此,对throttle()的调用调用updateModelData(),然后返回undefined,因为updateModelData()返回undefine。

以下是一些可能澄清这一点的示例代码:

var foo = (x) => x;
var leading = _.throttle(foo, DELAY, {leading: true, trailing: false}); //these are the default options for leading and trailing
var trailing = _.throttle(foo, DELAY, {leading: false, trailing: true});
leading(1); //Calls foo(1), returns 1
leading(2); //Doesn't call foo, returns 1, 
leading(3); //Doesn't call foo, returns 1
trailing(1); //Doesn't call foo, returns undefined
trailing(2); //Doesn't call foo, returns undefined
//DELAY ms later
//foo(2) is called, due to the most recent call to bar2
leading();  //Calls foo(), returns undefined 
leading(1); //Still returns undefined from above
trailing(); //Doesn't call foo, returns 2
trailing(1); //Doesn't call foo, returns 2
//Another DELAY ms later
leading("Whatever"); //Calls foo("Whatever"), returns "Whatever";

这是您的JSFiddle的一个版本,它也使它变得更加明显。


实际上,你不应该仅仅为了获取函数返回的最后一个值而调用它,所以我建议你自己管理最后一个数值,而不是依赖_.throttle来为你做这件事。例如:

var lastResultOfFoo;
var foo = function (x) {
    lastResultOfFoo = x;
    return x;
}
//OR (if you don't mind attaching arbitrary properties to functions)
var foo = function (x) {
    foo.lastResult = x;
    return x;
}

以下代码运行良好:

var throttled = _.throttle(updateModelData, 1000);
var i = 0;
function updateModelData(data) {
    return data;
}
var interval = setInterval(function() {
    console.log(throttled(i++));
    if (i === 6) {
        clearInterval(interval);
        console.log('Last value: ' + throttled());
    }
}, 2000);

输出:

0
1
2
3
4
5
"Last value: 5"

DEMO