DataTablesSrc icon indicating copy to clipboard operation
DataTablesSrc copied to clipboard

Fix: util.throttle misbehavior

Open ml1nk opened this issue 8 years ago • 2 comments

In my opinion, the current implementation of $.fn.dataTable.util.throttle shows unexpected behavior if the timing is unfavorable:

  1. The time between two consecutive fn calls should be equal or greater than the given frequency
  2. fn should always be called with scope and arguments of the last tfn (throttled function) call

An example of this misbehavior is at the following link: https://repl.it/Nq7e/48

I acknowledge that my contribution is offered under the MIT license.

ml1nk avatar Nov 11 '17 02:11 ml1nk

Awesome - thanks for this! I'm not going to merge this in to 1.10 if that's okay as I've started a 2.0 branch now and plan to do some work on the throttle there (also introducing a debounce option).

Looking at the code, that is an improvement on mine - thanks. It does however have the same issue as mine in that it is calling the callback immediately when triggered and then again after the timeout period. That is one of the things I plan to address. I'll do so in 2.0.

Thanks again.

DataTables avatar Nov 11 '17 11:11 DataTables

I'm looking forward to see 2.0 as this project is already a very good one.

it is calling the callback immediately when triggered and then again after the timeout period

An immediate callback is probably optimal in most cases, because the additional setTimout is just overhead if there isn't a explicit reason to do so, for example if throttling events. In addition code that depends on this behavior breaks, like detection if the throttled function wasn't called recently before. At least there should be some kind of switch for this.

It could be something like the following:

function throttle(fn, freq, delayed) {
		var
			frequency = freq !== undefined ? freq : 200,
			call,
			that,
			timer;

		function timeout(direct) {
			if(direct && delayed) {
		   		setTimeout( function () {
		    			fn.apply(that, call);
				}, 0 );
			} else {
				fn.apply(that, call);
		 	}
			call = undefined;
			that = undefined;
			timer = setTimeout(function () {
				timer = undefined;
				if (call) {
					timeout(false);
				}
			}, frequency);
		}

		return function () {
			that = this;
			call = arguments;
			if (!timer) {
				timeout(true);
			}
		};
}

ml1nk avatar Nov 11 '17 15:11 ml1nk