Image stabilization

Usage scenarios

It is generally possible to retrieve data after user input has stopped for some time, rather than every input, as shown below:

The implementation code

  function debounce<Return> (fn: (... params: any[]) = >Return.wait: number/** Wait time */immediate: boolean/** Whether to execute immediately */):Executor<Return> {
    const now: (a)= > number = Date.now.bind(Date);
    let lastTime: number = 0;
    let timer: number = null;
    let params: IArguments = null;
    let _this: Function | null = null;

    function later() :void {
      const nowTime: number = now();

      if (nowTime - lastTime < wait) {
        // If there is not enough time to wait, continue waiting
        const remainTime = wait - (nowTime - lastTime);

        timer = setTimeout(later, remainTime);
      } else {
        // The waiting time is up. Execute the callback
        debouncer.result = fn.apply(_this, params);

        timer = null;
        _this = null;
        params = null; }}function execute() : (Return | null) {
      lastTime = now();
      _this = this;
      params = arguments;

      try {
        if (immediate && timer === null) {
          // Execute immediately
          debouncer.result = fn.apply(_this, params);
        }

        return debouncer.result;
      } finally {
        if (timer === null) {
          // Join the queue for executiontimer = setTimeout(later, wait); }}}// Create the actuator
    const debouncer: Executor<Return> = {
      execute,
      result: null};return debouncer;
  };
Copy the code

The principle is very simple, mainly to judge whether the waiting time is reached, if not, continue to join the task queue waiting for execution. Usage:

import utils from '.. /index';

const input = document.querySelector('input');
const executor = utils.fn.debounce(function(value) {
  console.log('fetch');
  
  return value;
}, 300);

let value = null;

input.addEventListener('input'.function(e) {
  executor.execute(e.target.value);
  value = executor.result;
});
Copy the code

The reason for returning an actuator is that it is easy to get the value returned the last time the function was executed.

The throttle

Usage scenarios

Some events can be triggered less frequently. For example, the position of the scroll bar should be monitored during lazy loading, but it does not need to be triggered every time it slides, which can reduce the frequency of calculation without wasting resources. There are also goods preview magnifying glass effect, do not have to calculate the position of every mouse movement.

The implementation code

throttle: function <Return> (fn: (... params: any[]) = >Return.wait: number.{
      isExecuteAtStart = true,
      isExecuteAtEnd = true,
    }: ThrottleOptions = {
      isExecuteAtStart: true.isExecuteAtEnd: true,
    }
  ): Executor<Return> {
    let timer: number = null;
    let _this: Function = null;
    let params: IArguments = null;

    function execute() : (Return | null) {
      _this = this;
      params = arguments;

      if (isExecuteAtStart && timer === null) {
        // If you need to start executing without a timer
        executor.result = fn.apply(_this, params);
        _this = null;
        params = null;
      }

      if (isExecuteAtEnd) {
        // If you need to execute it at the end
        if (timer === null) {
          timer = setTimeout(function () {
            executor.result = fn.apply(_this, params);
            _this = null;
            params = null;
            timer = null; }, wait); }}return executor.result;
    }

    const executor: Executor<Return> = {
      execute,
      result: null
    };

    return executor;
}
Copy the code

The last

The purpose of both anti-shake and throttling is to reduce unnecessary calculations, not waste resources, and only trigger calculations when appropriate. The source code can be seen in the fn module of this project, and there are many practical functions, welcome to use and learn. If my article is of some help to you, please click “like”, thanks ~