简体   繁体   中英

Rate limiting an .apply method with _.throttle

Is it possible to rate-limit, throttle or debounce something like this[act].apply(this, data) ? With underscore or something else? I've tried a bunch of stuff, like

_.throttle(/* different permutations of combined args */)

_.throttle.apply(/* same */)

_.throttle.apply(myArgs)(throttleArgs)

_.throttle(throttleArgs).apply(myArgs)

etc. Some yield errors, some freeze execution and some call the apply method with (correct scope and args but) no throttling. Any ideas? Using CoffeeScript and these are class methods.

Since the original function you are calling

this[act].apply(this, data)

uses this , I assume you are calling it from within a method on an object. The question, how to get this from here to there? Many higher-order functions are designed to call the underlying function with the same this they themselves are called with, using the following kind of skeleton:

function higher_order_function(fn) {
  return function() {
    return fn.apply(this, arguments);
  };
}

What this means is, if I have a object with a method

var obj = {
  val: 42,
  print: function() { console.log(this.val); }
}

And then I want to transform the print function:

obj.newPrint = higher_order_function(obj.print);

I can now call obj.newPrint , and underneath, this will be used to invoke print , and everything works as expected.

There are alternative designs for such things, involving passing around contexts ( this ) explictly and giving them as separate parameters to functions, but the approach above is usually cleaner and "just works".

This is how _.throttle works. If you look at the source code, you see it doing things like

return function() {
  ...
  context = this;
  args = arguments;
  ...
  result = func.apply(context, args);
};

This means, to invoke your code in throttled fashion, all you need to do is arrange to call it with this .

Let's assume the original code you are calling is in a function called act .

var obj = {
  act: function(act) {
    this[act].apply(this, data);
  }
};

To make a throttled version of act (here, we make it directly on the object; you could accomplish a similar thing by putting it on the prototype, see below):

obj.throttledAct = _.throttle(obj.act);

Then simply call

obj.throttledAct('act1')

If you are programming with prototypes:

Foo.prototype.func = function(act) { this[act].apply(this, data) };

Then you can put the throttled version on the prototype with:

Foo.prototype.throttledFunc = _.throttle(Foo.prototype.func);

and everything will work as expected.

If for some reason you want to create a stand-alone version of the throttled function, without putting it in an object or or prototype:

var throttledFunc = _.throttled(func);

You can then call it with call or apply to force the value of this :

throttledFunc.call(obj, 'act1`);

But in either case, how does the parameter 'act1' get passed through to the underlying function. This is also accomplished via the line in the implementation of _.throttle that reads

result = func.apply(context, args);

Here args is the arguments being passed to the function constructed by _.throttle , and apply is used to pass them, along with this , to the underlying function. Note that _.throttle itself also takes additional parameters to be passed to the underlying function, but that "burns them in" rather than letting them be specified each time the throttled function is called.

Your attempts

_.throttle(/* different permutations of combined args */)
_.throttle.apply(/* same */)
_.throttle.apply(myArgs)(throttleArgs)
_.throttle(throttleArgs).apply(myArgs)

All of these suffer from the same problem, which is that _.throttle must be passed a function to be throttled, and returns a function which you then call to obtain the throttled behavior. The last one is possibly closest, assuming that throttleArgs is the function to be throttled, and myArgs is actually this, myArgs .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM