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

How to get last value from throttled function

_.throttle 函数的文档指出:

Creates a throttled function that only invokes func at most once per every wait milliseconds. The throttled function comes with a cancel method to cancel delayed func invocations and a flush method to immediately invoke them. Provide an options object to indicate whether func should be invoked on the leading and/or trailing edge of the wait timeout. The func is invoked with the last arguments provided to the throttled function. Subsequent calls to the throttled function return the result of the last func invocation

我对这一行感兴趣:

Subsequent calls to the throttled function return the result of the last func invocation

我试过:

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() 触发函数而不返回数据。我如何调用它以便它 returns 最后一个数据?

编辑:

根据源代码,只有在不存在挂起的函数调用时才会返回该值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);

以下代码工作正常:

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

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

这意味着 "result of the last function invocation" 可能是由您对受限函数的 当前 调用引起的函数调用的结果。因此,您对 throttle() 的调用会调用 updateModelData(),然后调用 returns 未定义,因为 updateModelData() returns 未定义。

这里有一些示例代码可以阐明这一点:

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;
}