js function anti-jitter and function throttling

Keywords: REST Spring Attribute Javascript

Difference

debounce: When an action is invoked in n milliseconds, the action is executed. If the action is invoked in n milliseconds, the execution time will be recalculated. For example, if you hold a spring with your finger, it will not bounce until you let go.

Throttle (throttle): Pre-set an execution cycle, when the time of calling an action is greater than or equal to the execution cycle, then execute the action, and then enter the next new cycle. For example, if you tighten the tap until the water runs out in the form of droplets, you will find that every other time, a drop of water will flow out.

Applicable scenarios

  • resize and scroll events of window s objects

  • Mosemove event when dragging

  • Mosedown and keydown events in shooting games

  • keyup events for text input and automatic completion

In fact, for resize events in window s, the actual requirements are mostly to stop changing the size of n milliseconds after the execution of follow-up processing (anti-jitter); while for most other events, the need is to perform follow-up processing (throttling) at a certain frequency.

Add an auxiliary function restArgs

/**
     * Implementation of ES6-like rest parameters to enable a function to support rest parameters
     * @param func Functions requiring rest parameters
     * @param startIndex Where to start identifying the rest parameter, if not passed, the last parameter is the rest parameter by default
     * @returns {Function} Returns a function with rest parameters
     */
    var restArgs = function (func, startIndex) {
        // Where does the rest parameter start? If not, the last parameter of the function is regarded as the rest parameter by default.
        // Notice that the length attribute of the function object reveals the number of parameters of the function.
        /*
         ex: function add(a,b) {return a+b;}
         console.log(add.length;) // 2
         */r
        startIndex = startIndex == null ? func.length - 1 : +startIndex;
        // Returns a function that supports rest parameters
        return function () {
            // Correct parameters to avoid negative values
            var length = Math.max(arguments.length - startIndex, 0);
            // Create Array Storage for rest Parameters
            var rest = Array(length);
            // Assume that the parameters start from two: func(a,b,*rest)
            // Call: func(1,2,3,4,5); the actual call is: func.call(this, 1,2, [3,4,5]);
            for (var index = 0; index < length; index++) {
                rest[index] = arguments[index + startIndex];
            }
            // Depending on the rest parameter, call the function in different situations. It should be noted that the rest parameter is always the last parameter, otherwise there will be ambiguity.
            switch (startIndex) {
                case 0:
                    // call parameters passed one by one
                    return func.call(this, rest);
                case 1:
                    return func.call(this, arguments[0], rest);
                case 2:
                    return func.call(this, arguments[0], arguments[1], rest);
            }
            // If it's not the three cases above, it's more general (it should be the author's writing that finds that the switch case may be longer and longer, apply is used).
            var args = Array(startIndex + 1);
            // Get the front parameters first
            for (index = 0; index < startIndex; index++) {
                args[index] = arguments[index];
            }
            // Remaining parameters on stitching
            args[startIndex] = rest;
            return func.apply(this, args);
        };
    };

debounce

Returns a rebound-proof version of the function, delaying the execution of the function (true execution) after the wait milliseconds at the last time the function is called. This is helpful for the behavior that must be performed after some input (mostly user operations) has stopped arriving. For example, render a Markdown-formatted comment preview, recalculate the layout when the window stops resizing, and so on.

The argument immediate is true, and debounce calls this function at the beginning of the wait interval. It's useful in situations like accidentally clicking the submit button twice and submitting it twice.

var debounce = function (func, wait, immediate) {
        var timeout, result;

        var later = function (context, args) {
            timeout = null;
            if (args) result = func.apply(context, args);
        };

        var debounced = restArgs(function (args) {
            // Once timeout exists, it means that func has been tried before
            // Since debounce only recognizes the latest call, FuncS waiting to be executed before are terminated
            if (timeout) clearTimeout(timeout);
            // If new calls are allowed to attempt immediate execution,
            if (immediate) {
                // If no call attempt has been made before, the call can be executed immediately, otherwise it must wait until the execution is completed.
                var callNow = !timeout;
                // Refresh timeout
                timeout = setTimeout(later, wait);
                // If it can be executed immediately, it will be executed immediately.
                if (callNow) result = func.apply(this, args);
            } else {
                // Otherwise, the attempt call will delay wait for a period of time
                timeout = delay(later, wait, this, args);
            }

            return result;
        });

        debounced.cancel = function () {
            clearTimeout(timeout);
            timeout = null;
        };

        return debounced;
    };

throttle

Create and return a function like a throttle valve, which is called at least once every wait millisecond when the function is called repeatedly. It is helpful to control some events with high triggering frequency. (Fool's Wharf Note: For more information: throttle and debounce of javascript functions, thanks to Mr. Austria for his translation suggestions)

By default, throttle will execute the function as soon as possible in the first time you call it, and if you call any number of functions in the wait cycle, they will be overwritten as soon as possible. If you want to disable the first execution, pass {leading: false} and if you want to disable the last execution, pass {trailing: false}.

var throttle = function (func, wait, options) {

        var timeout, context, args, result;
        // The last time func was called
        var previous = 0;
        if (!options) options = {};

        // Create a delayed function to wrap func's execution
        var later = function () {
            // When executed, refresh the last call time
            previous = options.leading === false ? 0 : new Date();
            // Cleaning timer
            timeout = null;
            result = func.apply(context, args);
            if (!timeout) context = args = null;
        };

        // Returns a function of throttled
        var throttled = function () {
            // The throttling function begins to execute.
            // When we try to call func, we first record the current timestamp
            var now = new Date();
            // Is it the first call?
            if (!previous && options.leading === false) previous = now;
            // How long does func have to wait to be called = the default minimum waiting period - (current time - last time of call)
            // Obviously, if options.leading = false is not set for the first call, then remaing=0, and func will be executed immediately.
            var remaining = wait - (now - previous);
            // Context and parameters required for execution after recording
            context = this;
            args = arguments;

            // If the calculation can be executed immediately
            if (remaining <= 0 || remaining > wait) {
                // Clear up the previous "latest call"
                if (timeout) {
                    clearTimeout(timeout);
                    timeout = null;
                }
                // Refresh the time point of the last func call
                previous = now;
                // Perform func calls
                result = func.apply(context, args);
                // If timeout is cleared,
                if (!timeout) context = args = null;

            } else if (!timeout && options.trailing !== false) {
                // If trailing edge is set, execution of this call attempt is suspended
                timeout = setTimeout(later, remaining);
            }
            return result;
        };

        // Throttling of functions can be cancelled
        throttled.cancel = function () {
            clearTimeout(timeout);
            previous = 0;
            timeout = context = args = null;
        };

        return throttled;
    };

Posted by Firestorm ZERO on Tue, 26 Mar 2019 04:42:28 -0700