Vue's guide to pitfalls using throttling functions

Vue's guide to pitfalls using throttling functions

Preface

In a common business scenario, we need to send a related request to obtain search data after the input in the search box is completed. Frequent event triggering will result in too frequent interface requests. Therefore, we need to limit this to prohibit unnecessary requests to avoid wasting resources~

Take a business scenario

concept:

Introduction to anti-shake function

About addEventListener

Example of use:

    function debounce(fn) {
        let timeout = null; // Create a marker to store the return value of the timer return function () {
            clearTimeout(timeout); // Clear the previous setTimeout every time the user enters input timeout = setTimeout(() => {
                // Then create a new setTimeout, so that if there is more input within the interval after the input character, the fn function will not be executed fn.apply(this, arguments);
            }, 500);
        };
    }
    function sayHi() {
        console.log('Anti-shake success');
    }

    var inp = document.getElementById('inp');
    inp.addEventListener('input', debounce(sayHi)); // Anti-shake

Use in vue?

First, let me talk about my previous pitfalls.

The following code is a simplified version of a scene

function debounce(fn) {
        let timeout = null; // Create a marker to store the return value of the timer return function () {
            clearTimeout(timeout); // Clear the previous setTimeout every time the user enters input timeout = setTimeout(() => {
                // Then create a new setTimeout, so that if there is more input within the interval after the input character, the fn function will not be executed fn.apply(this, arguments);
            }, 500);
        };
   }

Wrong way of using

<template>
    <div class="search-view">
        <div class="header">
            <Search 
                class="search-box" 
                v-model='searchValue' 
                @input = 'getSearchResult' 
                placeholder='Search for the good stuff you want' />
            <span @click="goBack" class="cancel">Cancel</span>
        </div>
        <div class="serach-view-content" />
    </div>

</template>

<script>
import Search from './components/Search';
import debounce from './config';

export default {
    name: 'SearchView',
    components:
        Search
    },
    data() {
        return {
            searchValue: ''
        };
    },
    methods: {
        getSearchResult() {
            debounce(function() {
                console.log(this.searchValue);
            })();
        }
    }
};
</script>

Why is it wrong?

Source code level analysis

Vue template compilation parsing event

export const onRE = /^@|^v-on:/
export const dirRE = /^v-|^@|^:/

function processAttrs(el) {
  const list = el.attrsList
  let i, l, name, value, modifiers
  for (i = 0, l = list.length; i < l; i++) {
    name = list[i].name
    value = list[i].value
    if (dirRE.test(name)) {
      // Parsing modifiers modifiers = parseModifiers(name)
      if (modifiers) {
        name = name.replace(modifierRE, '')
      }
      if (onRE.test(name)) { // v-on
        name = name.replace(onRE, '')
        addHandler(el, name, value, modifiers, false, warn)
      }
    }
  }
}

Summary: The initialization event function initEvents called during the instance initialization phase actually initializes the events triggered in the listener child component registered by the parent component using v-on or @ in the template.

Vue's event mechanism

Vue.prototype.$on = function(event, fn) {
    const vm = this;
    if (Array.isArray(event)) {
        for (let i = 0; i < event.length; i++) {
            this.$on(event[i], fn);
        }
    } else {
        //This _events attribute is used as the event center of the current instance. All events bound to this instance will be stored in the event center _events attribute.
        (vm._events[event] || (vm._events[event] = [])).push(fn);
    }
    return vm;
};

Vue.prototype.$emit = function(event) {
    const vm = this;
    let cbs = vm._events[event];
    if (cbs) {
        cbs = cbs.length > 1 ? toArray(cbs) : cbs;
        let args = toArray(arguments, 1);
        for (let i = 0; i < cbs.length; i++) {
            try {
                cbs[i].apply(vm, args);
            } catch (e) {
                handleError(e, vm, `event handler for "${event}"`);
            }
        }
    }
    return vm;
};

The initMethods method is called in vue's initState

In initMethods, hang the methods method on this

for (const key in methods) {
        if (process.env.NODE_ENV !== 'production') {
            if (methods[key] == null) {
                warn(
                    `Method "${key}" has an undefined value in the component definition. ` +
                        `Did you reference the function correctly?`,
                    vm
                );
            }
            // If the name is the same as a property name in props, an exception is thrown if (props && hasOwn(props, key)) {
                warn(`Method "${key}" has already been defined as a prop.`, vm);
            }
            /*
            If a method name in methods already exists in the instance vm and the method name starts with _ or $, an exception is thrown:
            Prompt the user that the method name is not standardized*/
            if (key in vm && isReserved(key)) {
                warn(
                    `Method "${key}" conflicts with an existing Vue instance method. ` +
                        `Avoid defining component methods that start with _ or $.`
                );
            }
            // Bind method to instance vm so that we can access it through this.xxx // At the same time, if let m1 = this.xxx m1() in vue, this also points to vue
            vm[key] = methods[key] == null ? noop : bind(methods[key], vm);
        }

Key points:

  • Subcomponent $emit('input event')
  • Parent component receives events
getSearchResult.apply(this, agrs)
<===> The call of apply can be written as follows this.getSearchResult(args)

// And then it becomes this execution debounce(function() {
      console.log(this.searchValue);
})();

// Here debounce returns a function so it becomes (function (fn) {
      clearTimeout(timeout); // Clear the previous setTimeout every time the user enters input timeout = setTimeout(() => {
          // Then create a new setTimeout, so that if there is more input within the interval after the input character, the fn function will not be executed fn.apply(this, arguments);
      }, 500);
})()
// At this point, it actually becomes the self-execution of the anonymous function // Since each time the input is triggered, a new anonymous function will be returned to generate a new function execution stack, so the anti-shake function fails~

So how should we call

<template>
    <div class="search-view">
        <div class="header">
            <Search
                class="search-box"
                v-model='searchValue'
                @input = 'getSearchResult()'
                placeholder='Search for the good stuff you want'
            />
            <span
                @click="goBack"
                class="cancel">Cancel</span>
        </div>
        <div class="serach-view-content">
            
        </div>
    </div>

</template>

<script>
import debounce from 'lodash.debounce';
export default {
    name: 'SearchView',
    components:
        Search,
    },
    data() {
        return {
            searchValue: '',
        };
    },
    methods: {
        getSearchResult:debounce(function () {
            console.log(this.searchValue);
        }, 500),
    },

};
</script>

Analyze the execution process

getSearchResult().apply(this, args)
<===> Ignore parameter behavior and only focus on the execution stack let func = function () {
    clearTimeout(timeout); // Clear the previous setTimeout every time the user enters input timeout = setTimeout(() => {
        // Then create a new setTimeout, so that if there is more input within the interval after the input character, the fn function will not be executed fn.apply(this, arguments);
    }, 500);
};

this.func(args)

<===>

The behavior of the subcomponent triggering the input always returns the same function body. Anti-shake is successful.

Similar to addEventListener introduced at the beginning of the article

Summarize

This is the end of this article about the pitfalls of using throttling functions in Vue. For more relevant content about the pitfalls of using throttling functions in Vue, please search for previous articles on 123WORDPRESS.COM or continue to browse the related articles below. I hope you will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • A brief discussion on the best solution for VUE anti-shake and throttling (functional components)
  • Example of how to encapsulate throttling functions using Vue custom directives
  • Vue implements the sample code of fuzzy query of input box (application scenario of throttling function)
  • Understanding and application of function anti-shake throttling in Vue
  • Causes and solutions for failure of throttling function in Vue components

<<:  centos 7 modify sshd | prohibit root login and sshd port script definition

>>:  MySQL data backup and restore sample code

Recommend

HTML+css to create a simple progress bar

1. HTML code Copy code The code is as follows: Ex...

Vue3 list interface data display details

Table of contents 1. List interface display examp...

Vue+Openlayer uses modify to modify the complete code of the element

Vue+Openlayer uses modify to modify elements. The...

Tutorial on installing MySQL 8.0.11 using RPM on Linux (CentOS7)

Table of contents 1. Installation preparation 1. ...

JavaScript to make the picture move with the mouse

This article shares the specific code of JavaScri...

Vue codemirror realizes the effect of online code compiler

Preface If we want to achieve the effect of onlin...

MySql development of automatic synchronization table structure

Development Pain Points During the development pr...

How to use css overflow: hidden (overflow hiding and clearing floats)

Overflow Hide It means hiding text or image infor...

JavaScript to achieve window display effect

This article shares the specific code of JavaScri...

Sample code for implementing neon button animation effects with CSS3.0

Today I will share with you a neon button animati...

CSS implements the web component function of sliding the message panel

Hello everyone, I wonder if you have the same con...

Summary of various methods of implementing article dividing line styles with CSS

This article summarizes various ways to implement...

Install mysql5.7 on Ubuntu 18.04

Ubuntu 18.04 installs mysql 5.7 for your referenc...

WML tag summary

Structure related tags ---------------------------...