Throttling and stabilization are used to prevent multiple calls to the function. The difference is that if the user keeps firing the function and the interval between each firing is less than the threshold, the function will only be called once in the case of stabilization, whereas throttling will call the function at regular intervals.

Function image stabilization

The callback is executed n seconds after the event is triggered, and if it is triggered again within n seconds, the timer is reset.

<! DOCTYPEhtml>
<html>
<head>
	<title>Throttling and anti-shaking</title>
	<meta charset="utf-8">
	<style>
	    #container{
	        width: 100%; height: 200px; line-height: 200px; text-align: center; color: #fff; background-color: # 444; font-size: 30px;
	    }
    </style>
</head>
<body>
 <div id="container"></div>
 <script type="text/javascript">
	var count = 1;
	var container = document.getElementById('container');

	function getUserAction() {
	    container.innerHTML = count++;
	};

	// container.onmousemove = getUserAction;
	container.onmousemove = debounce(getUserAction, 1000);

	function debounce(func, wait) {
	    var timeout;
	    return function () {
	        clearTimeout(timeout)
	        timeout = setTimeout(func, wait); }}</script>
</body>
</html>
Copy the code

The idea here is to create a timer, rewrite the onMousemove method, once triggered onMousemove, first clear the timer, then start a timer, after the specified time to execute the function. This provides a simple stabilization, and the repeated trigger function is executed only once within a specified period of time. The problem of frequent repeated triggering was solved very well, but because the onMousemove function was overwritten directly, both this and event were lost.

Normally, in onMousemove, this would point to the object calling the function, namely container, because debounce returns the function that actually overwrites onMousemove, creating a closure that causes this to be lost. This specifies that this refers to apply and call methods. The only difference in usage is for arguments. Call requires an array, so apply is used.

The modified debounce function is:

function debounce(func, wait) {
    var timeout;
    return function () {
        var context = this;
        clearTimeout(timeout)
        timeout = setTimeout(function(){ func.apply(context) }, wait); }}Copy the code

Resolve the event argument. Normally there is an event in the onMousemove function that points to the current event object. Because debounce returns an anonymous function, arguments can be obtained via the arguments property, which is a class array of function arguments.

Modified debounce:

function debounce(func, wait) {
    var timeout;

    return function () {
        var context = this;
        var args = arguments;

        clearTimeout(timeout)
        timeout = setTimeout(function(){ func.apply(context, args) }, wait); }}Copy the code
Function of the throttle

Specifies that a function can fire only once per unit of time. If the function fires more than once per unit of time, only one of these fires takes effect.

Depending on whether or not it is executed the first time and whether or not it is executed after the end, the effect and the way it is implemented will vary. We use leading to indicate whether it will be executed the first time and trailing to indicate whether it will be executed again after the end.

There are two main ways to implement throttling, one is to use time stamps, the other is to set timers.

  • Use time stamps

    When the time is triggered, we take the current timestamp, then subtract the previous timestamp, execute the function if it is greater than the set time period, then update the timestamp to the current timestamp, if it is less than, do not execute.

    function debounce(func, wait) {
        var timeout;
    
        return function () {
            var context = this;
            var args = arguments;
    
            clearTimeout(timeout)
            timeout = setTimeout(function(){ func.apply(context, args) }, wait); }}Copy the code
  • Use timer

    When the event is triggered, we set a timer, and when the event is triggered, if the timer exists, it is not executed until the timer is executed, and then the function is executed to clear the timer so that the next timer can be set.

    function throttle(func, wait) {
        var timeout;
        var previous = 0;
    
        return function() {
            context = this;
            args = arguments;
            if(! timeout) { timeout =setTimeout(function(){
                    timeout = null;
                    func.apply(context, args)
                }, wait)
            }
    
        }
    }
    Copy the code

    In both of these ways, the function is placed in the timer, js will not execute the function immediately, because JS is single-threaded, the function in the timer is asynchronous function, asynchronous function will be placed in the event queue, when the synchronous code is finished, the code in the event queue will be executed in turn. If you need to change the function immediately, you need to make a small change:

    function throttle(func, wait) {
        var timeout, context, args, result;
        var previous = 0;
    
        var later = function() {
            previous = +new Date(a); timeout =null;
            func.apply(context, args)
        };
    
        var throttled = function() {
            var now = +new Date(a);// The time remaining for the next func trigger
            var remaining = wait - (now - previous);
            context = this;
            args = arguments;
             // If there is no time left or you change the system time
            if (remaining <= 0 || remaining > wait) {
                if (timeout) {
                    clearTimeout(timeout);
                    timeout = null;
                }
                previous = now;
                func.apply(context, args);
            } else if(! timeout) { timeout =setTimeout(later, remaining); }};return throttled;
    }
    Copy the code

    This way have a clever place is he calculated the remaining time of the next trigger function, according to the above the timestamp way throttling is to directly compare the current timestamp with a timestamp, here with interval minus the current timestamp with a timestamp, the difference between the calculation result is the function the next trigger the rest of the time, if the remaining time is greater than zero, Indicates that the throttling function will be stopped, the timer cleared immediately, and the function executed immediately.

    Full code: github.com/jinxudong99…