Any intention of providing a function.throttle?

已查看 34 次
跳至第一个未读帖子

Ignacio Coloma

未读,
2009年4月21日 16:01:562009/4/21
收件人 prototy...@googlegroups.com
Hi, the idea was showcased some time ago in ajaxian:

http://ajaxian.com/archives/delaying-javascript-execution

It's a step  further what delay() does, to avoid event repetition. The immediate use is for onMouseMove handlers, where taking immediate action may not be a good idea.

We are right now implementing it for a project, but first I wanted to know if there are any plans of including something similar for prototype.

Best,

Nacho.

Mislav Marohnić

未读,
2010年4月23日 06:28:352010/4/23
收件人 prototy...@googlegroups.com
I wanted to propose Function#throttle for core, only to find out it was suggested here on the list exactly a year ago:

Here is my implementation:

  Function.prototype.throttle = function(t) {
    var timeout, fn = this
    return function() {
      timeout && clearTimeout(timeout)
      timeout = setTimeout(fn.curry.apply(fn, arguments), t)
    }
  }

The `t` argument is time in milliseconds. This method returns a function that, in the series of calls that are less than value of `t` apart, executes the original function only once, at the end.

I use it primarily for "keyup" events (where this is absolutely essential), but it has other uses.

The feedback I wanted to get here is naming. The jQuery community calls this function "debounce", because "throttling" means letting through a function execution at regular intervals. I agree about the last part, but I simply don't like "debounce" since it's completely non-descriptive to me.

--
You received this message because you are subscribed to the Google Groups "Prototype: Core" group.
To post to this group, send email to prototy...@googlegroups.com
To unsubscribe from this group, send email to prototype-cor...@googlegroups.com
For more options, visit this group at http://groups.google.com/group/prototype-core?hl=en

Mislav Marohnić

未读,
2010年4月23日 06:43:042010/4/23
收件人 prototy...@googlegroups.com
On Fri, Apr 23, 2010 at 12:28, Mislav Marohnić <mislav....@gmail.com> wrote:

Here is my implementation:

I noticed there might be a bug with preserving scope in my original implementation. Here is the revised version:

  Function.prototype.throttle = function(t) {
    var timeout, fn = this
    return function() {
      var scope = this, args = arguments
      timeout && clearTimeout(timeout)
      timeout = setTimeout(function() { fn.apply(scope, args) }, t)
    }
  }

And a usage example:

var typingHandler = textarea.on("keyup", function(e) { ... }.throttle(300))


Nacho Coloma

未读,
2010年4月23日 07:11:362010/4/23
收件人 prototy...@googlegroups.com
That's a step better than my own implementation. So, will it get into core?

Mislav Marohnić

未读,
2010年4月23日 07:31:172010/4/23
收件人 prototy...@googlegroups.com
2010/4/23 Nacho Coloma <ico...@gmail.com>
That's a step better than my own implementation.

Thanks, guys. But honestly, it's not something that hasn't be done before. I'm just proposing formalizing it.

About core, that's up to Tobie and Andrew. But what do you guys think about naming? And how would you implement a real throttling function; one that lets a call through at regular intervals? Should we have both?

j...@wikizzle.org

未读,
2010年4月23日 08:16:182010/4/23
收件人 prototy...@googlegroups.com

>
> Thanks, guys. But honestly, it's not something that hasn't be done
before.
> I'm just proposing formalizing it.
>
> About core, that's up to Tobie and Andrew. But what do you guys think
about
> naming? And how would you implement a real throttling function; one that
> lets a call through at regular intervals? Should we have both?

I have an implementation that I've been using for a while. See below.
It returns a function that will only run (rate) ms after it was last
called. Otherwise, it will do nothing.
If defer is set, instead of doing nothing, it schedules the function to be
called at the soonest possible time without breaking the restriction on
call frequency.


Function.prototype.maxrate =
function( rate, defer )
{
var lastcalled = 0;
var f = this;
var scheduled = -1;

return function()
{
var now = new Date().getTime();
var nextchance = lastcalled + rate;

//$log( 'now is ' + now + ',' + ' I last ran at ' +
lastcalled );
//$log( "I refuse to run before " + nextchance );

if( now > nextchance )
{
//$log( "...so I guess I will be running then!" );

lastcalled = now;
return f.apply( this, arguments );
}

//$log( "defer: " + defer + ", scheduled: " + scheduled
);
if( defer && scheduled == -1 )
{
//$log( "but since you asked so nicely, I'll
run in "
// + (nextchance - now) );

var obj = this;
var args = arguments;
scheduled = window.setTimeout(
function()
{
// $log( "defered call taking place" );
var now = new Date().getTime();

lastcalled = now;
f.apply( obj, args );
scheduled = -1;
}, nextchance - now );
}
};
};

Titi Alailima

未读,
2010年4月23日 09:00:132010/4/23
收件人 prototy...@googlegroups.com
On Fri, Apr 23, 2010 at 6:28 AM, Mislav Marohnić <mislav....@gmail.com> wrote:
I use it primarily for "keyup" events (where this is absolutely essential), but it has other uses.

The feedback I wanted to get here is naming. The jQuery community calls this function "debounce", because "throttling" means letting through a function execution at regular intervals. I agree about the last part, but I simply don't like "debounce" since it's completely non-descriptive to me.

"debounce" is a technical term, and it refers to the very case that you are trying to handle.  Physical controls tend to "bounce" and thus produce multiple events that you want to consolidate into a single event.  It may not be intuitive out of context, but it has a long history from the hardware world.  Coming from an electrical engineering background myself, I would be totally on board with using that terminology, but I could certainly be persuaded that something more intuitive would be in order.  However, "throttle" definitely seems to be the wrong way to go as it has a different meaning that is very intuitive.

Titi

Allen Madsen

未读,
2010年4月23日 10:09:032010/4/23
收件人 prototy...@googlegroups.com
I have used something like this in a project as well. I wouldn't mind
seeing it in core. I don't particularly care what its called.

Allen Madsen
http://www.allenmadsen.com

Mislav Marohnić

未读,
2010年4月23日 11:15:342010/4/23
收件人 prototy...@googlegroups.com
On Fri, Apr 23, 2010 at 15:00, Titi Alailima <tigre...@gmail.com> wrote:

"debounce" is a technical term, and it refers to the very case that you are trying to handle.

Thanks, Titi, for the insightful explanation.

Here is how I would implement a real throttle method:

  Function.prototype.throttle = function(t) {
    var timeout, scope, args, fn = this, tick = function() {
      fn.apply(scope, args)
      timeout = null
    }
    return function() {
      scope = this
      args = arguments
      if (!timeout) timeout = setTimeout(tick, t)
    }
  }

It's really just a twist on the original method in a way that it fires every `t` milliseconds, and calls in-between do nothing except update the scope and arguments. If the first argument is an event object, you definitely want the last event object of the series rather than the first one.

Andrew Dupont

未读,
2010年4月23日 13:28:492010/4/23
收件人 prototy...@googlegroups.com
I like this. I don't particularly care what we call it.

Too late for 1.7, naturally, but perhaps 1.7.1 or 1.8...

Cheers,
Andrew

"Cowboy" Ben Alman

未读,
2010年4月25日 17:08:402010/4/25
收件人 Prototype: Core
I tried posting this the other day, but my post didn't come through
for some reason. I've got a snippet of code that will allow you to
either throttle or debounce a function, in multiple ways. Granted, my
implementation does not use the Function prototype, but that would be
trivial to implement.

(And please don't mind the "jQuery" in the name, it doesn't require
jQuery in any way, it just uses it as an optional namespace!)

http://benalman.com/projects/jquery-throttle-debounce-plugin/

Either way, if you find any of the code useful, feel free to use it!

- Ben


On Apr 23, 1:28 pm, Andrew Dupont <goo...@andrewdupont.net> wrote:
> I like this. I don't particularly care what we call it.
>
> Too late for 1.7, naturally, but perhaps 1.7.1 or 1.8...
>
> Cheers,
> Andrew
>
> On Apr 23, 2010, at 10:15 AM, Mislav Marohnić wrote:
>
>
>
>
>
> > On Fri, Apr 23, 2010 at 15:00, Titi Alailima <tigreti...@gmail.com> wrote:
>
> > "debounce" is a technical term, and it refers to the very case that you are trying to handle.
>
> > Thanks, Titi, for the insightful explanation.
>
> > Here is how I would implement a real throttle method:
>
> >   Function.prototype.throttle = function(t) {
> >     var timeout, scope, args, fn = this, tick = function() {
> >       fn.apply(scope, args)
> >       timeout = null
> >     }
> >     return function() {
> >       scope = this
> >       args = arguments
> >       if (!timeout) timeout = setTimeout(tick, t)
> >     }
> >   }
>
> > It's really just a twist on the original method in a way that it fires every `t` milliseconds, and calls in-between do nothing except update the scope and arguments. If the first argument is an event object, you definitely want the last event object of the series rather than the first one.
>
> > --
> > You received this message because you are subscribed to the Google Groups "Prototype: Core" group.
> > To post to this group, send email to prototy...@googlegroups.com
> > To unsubscribe from this group, send email to prototype-cor...@googlegroups.com
> > For more options, visit this group athttp://groups.google.com/group/prototype-core?hl=en
>
> --
> You received this message because you are subscribed to the Google Groups "Prototype: Core" group.
> To post to this group, send email to prototy...@googlegroups.com
> To unsubscribe from this group, send email to prototype-cor...@googlegroups.com
> For more options, visit this group athttp://groups.google.com/group/prototype-core?hl=en

Mislav Marohnić

未读,
2010年4月27日 05:52:162010/4/27
收件人 prototy...@googlegroups.com
On Sun, Apr 25, 2010 at 23:08, "Cowboy" Ben Alman <cow...@rj3.net> wrote:
I've got a snippet of code that will allow you to either throttle or debounce a function, in multiple ways.

Yes, this was among the existing plugins I saw. I also read the source, but I felt it was a bit too much for this functionality. Since you've written this plugin, can you take a look at my code (last 2 snippets on this thread) and tell me if there's anything I might have overlooked in my implementations?

"Cowboy" Ben Alman

未读,
2010年4月27日 10:09:302010/4/27
收件人 Prototype: Core
Mislav, this will minify slightly smaller (152b) than what you have
(156b):

Function.prototype.throttle = function( delay ) {
var fn = this,
timeout_id;

return function(){
var that = this,
args = arguments;

if ( !timeout_id ) {
timeout_id = setTimeout(function(){
fn.apply( that, args );
timeout_id = null;
}, delay);
}
};
};

That being said, this throttle (and yours) don't have an option for
disabling that final "deferred" execution. I have made a "prototype"
version of my jQuery plugin here, it has all the same functionality of
the jQuery version, but is called in a prototype-style way:
http://gist.github.com/380755

- Ben

Mislav Marohnić

未读,
2010年4月27日 10:19:432010/4/27
收件人 prototy...@googlegroups.com
On Tue, Apr 27, 2010 at 16:09, "Cowboy" Ben Alman <cow...@rj3.net> wrote:

That being said, this throttle (and yours) don't have an option for
disabling that final "deferred" execution.

What is the use case for disabling this final call? Or for forcing the intial call right at the start? I've noticed you have these options available in your plugin.

"Cowboy" Ben Alman

未读,
2010年4月27日 10:36:092010/4/27
收件人 Prototype: Core
Re. disabling the trailing execution during throttle: you might want a
function to execute every N milliseconds only while you're performing
an action. Perhaps it doesn't update a state value, but simple shows a
progress bar while the action is taking place. In this case, it would
be detrimental to perform that action after completion.

Re. debouncing at the beginning: if you're accepting input and only
want to register the first click but not subsequent clicks, this will
make an interface feel as responsive as possible while not allowing
accidental extra clicks.

Common use-cases:

Throttle, trailing: updating state (great for event handlers)
Throttle, no trailing: showing progress
Debounce, end: User input for expensive or asynchronous actions
Debounce, begin: User input for synchronous actions

I'm sure people can come up with many more examples, these were the
first that came to mind.

- Ben

On Apr 27, 10:19 am, Mislav Marohnić <mislav.maroh...@gmail.com>
wrote:
回复全部
回复作者
转发
0 个新帖子