preface

This is a very old topic, and one of the reasons why I brought it up is because I didn’t care about it, and some of the problems I’ve faced recently require these two tips; The second reason is that these two techniques bring a lot of optimization; Reason number three, as a refresher on closures.

You may encounter the following situations during development:

  • Listening to theWindowThe object’sresize.scrollThe event
  • Listen when you dragmousemove
  • In text input, processing of the input string, such as themarkdwonConverted tohtml
  • Listen for file changes and restart the service

In the first and third cases, events are frequently started within a short period of time. If there is a lot of calculation, frequent DOM manipulation, resource loading and other heavy behaviors in the event, it may cause UI to be stuck, or even make the browser crash. In the fourth case, some developers like to save the edited file by pressing Ctrl+S multiple times, which can be handled with a quick restart service, but restarting an application may result in multiple unnecessary restarts.

For this set of requirements, debounce and Throttle were the two solutions.

Function of the throttle

Function as a cycle, such as window binding to a resize event, as long as the window changes size to print 1, if you don’t use function throttling, when we will find the console window adjust the print 1, but using the function of throttling after that we will find the process of adjustment, every once in a while to print 1.

A simple implementation of function throttling:

/** ** @param func {Function} Actual Function * @param wait {Number} Execution interval, in milliseconds (ms), Default 100ms * * @return {Function} returns a "throttling" Function */

function throttle(func, wait = 100) {
   // Use closures to save timers and the last execution time
   let timer = null;
   let previous; // Last execution time
   return function() {
       // Save the context and parameters of the function call, passed to fn
       const context = this;
       const args = arguments;
       const now = +new Date(a);if (previous && now < previous + wait) { // in the cycle
           clearTimeout(timer);
   	    timer = setTimeout(function() {
   	        previous = now;
   	        func.apply(context, args);
   	    }, wait);
       } else{ previous = now; func.apply(context, args); }}; }Copy the code

The method used is also simple:

const btn = document.getElementById('btn');

function demo() {
   console.log('click');
}
btn.addEventListener('click', throttle(demo, 1000));
Copy the code

Listen for the resize event in the React window and the onChange event in the input box:

import React, { Component } from 'react';
import { throttle } from '.. /.. /utils/utils';

export default class Demo extends Component {
 constructor() {
   super(a);this.change = throttle((e) = > {
       console.log(e.target.value);
       console.log('throttle');
   }, 100);
 }
 
 componentDidMount() {
   window.addEventListener('resize', throttle(this.onWindowResize, 60));
 }
 
  componentWillUnmount() {
   window.removeEventListener('resize', throttle(this.onWindowResize, 60));
 }
 
 onWindowResize = (a)= > {
 	console.log('resize');
 }

 handleChange = (e) = > {
   e.persist();
   this.change(e);
 }

 render() {
   return (
       <input
         onChange={this.handleChange}
       />); }}Copy the code

Function to shake

After the event is triggered, the callback function will be executed after a certain time (N). If the event is triggered again within the waiting time, the callback function will be executed again until the event is not triggered within the event N. Then the function will be executed after the event N is triggered for the last time.

Window resize, if you keep changing the size of the window, it will not print 1. It will print 1 only after you stop changing the size of the window and wait for some time.

Function to shake simple implementation:

/** * @param func {Function} Actual Function * @param delay {Number} delay time, in milliseconds (ms) * @return {Function} */

function debounce(fn, delay = 1000) {
  let timer;

  // Returns a function that executes func at delay milliseconds after the end of a time interval
  return function () { 

    // Save the context and parameters of the function call, passed to func
    var context = this
    var args = arguments

    // The function is called to clear the timer
    clearTimeout(timer)

    // When the returned function is called for the last time (i.e. when the user has stopped a continuous operation),
    // Execute func after delay ms
    timer = setTimeout(function () { fn.apply(context, args); }, delay); }}Copy the code

Application scenarios: Listening for file changes and restarting applications:

const debounce = require('./debounce');

watcher.on('change', debounce((a)= > {
    const child = spawn('npm'['run'.'dev:electron'], {
      cwd,
      detached: true.stdio: 'inherit'
    })
    child.unref();
    electron.app.quit();
  }, delay));
Copy the code