Causes and Solutions of Failure of Throttle Function in vue Component

  • 2021-10-11 17:30:12
  • OfStack

Today, when using throttle function, I met a problem, and it took me half a day to find the reason, so I will make a summary here.

Throttling function

Some events of browser, such as resize, scroll, mousemove and so on. These events are triggered too frequently, and the callback functions bound to these events will be called constantly, which will increase the burden on the browser and lead to a very bad user experience. Therefore, the sages invented the throttle function. The simple version is as follows:


function throttle (f, wait = 200) {
 let last = 0
 return function (...args) {
 let now = Date.now()
 if (now - last > wait) {
  last = now
  f.apply(this, args)
 }
 }
}

Suppose there is an vue component svgMark. Elements rendered in this component redraw reDraw when the page window size changes, and throttle functions are used to prevent performance loss when redrawing. Under normal circumstances, the code is as follows:


<template>
 <div>{{ index }}</div>
</template>

<script>
import { throttle } from 'lodash'
export default {
 name: 'SvgMark',
 data() {
 return {
  index: 0
 }
 },
 mounted() {
 window.addEventListener('resize', this.reDraw)
 },
 beforeDestroy() {
 window.removeEventListener('resize', this.reDraw)
 },
 methods: {
 reDraw: throttle(function() {
  this.index++
 }, 500)
 }
}
</script>
</script>

Under normal circumstances, it is no problem to use it like this. However, there is a scenario where the throttle function fails when the component is loaded many times by the v-for loop:


<template>
 <div>
 <svgMark v-for="item in 10" :key="item.id" />
 </div>
</template>

At this time, no matter how many svgMark components are rendered, when the window size changes, only the redrawing of the first component and the first n cut component is triggered. Why didn't other components trigger? This is about to start from the beginning.

Throttling function

When the throttle function is initialized, it produces a closure, which holds the variable last, and this last records the last time the f function was executed. When the throttle function is triggered the next time, if the time now minus the last time last is less than the throttle time wait specified by us, the function f will not be executed.

Obviously, the first subcomponent produces an last when the throttle function is triggered, while the second subcomponent produces an now when the throttle function is triggered does not satisfy now-last > wait, so no redrawing code is performed. When the throttle function is triggered by the first n component, now-last is satisfied > The condition of wait was redrawn successfully.

vue component

The vue component in the code compilation phase, the method reDraw: throttle (function () {this. index + +}, 500) in the component svgMark has been compiled into a function similar to the following:


reDraw: ƒ (...args) {
 let now = Date.now()
 if (now - last > wait) {
 last = now
 f.apply(this, args)
 }
}

Because the function is a reference type, all reDraw in methods using the subcomponent svgMark point to the same memory address, which means that the reDraw methods of all subcomponents are the same function.

Because all components share the same throttle function, throttling will of course occur. So how to solve the problem? The right remedy is to let each component generate its own throttling function instead of sharing it. The code is as follows

Subcomponents:


<template>
 <div>{{ index }}</div>
</template>

<script>
import { throttle } from 'lodash'
export default {
 name: 'SvgMark',
 data() {
 return {
  index: 0
 }
 },
 mounted() {
 this.reDraw = throttle(() => {
  this.index++
 }, 500)
 window.addEventListener('resize', this.reDraw)
 },
 beforeDestroy() {
 window.removeEventListener('resize', this.reDraw)
 }
}
</script>

We manually declared the reDraw function in the mounted declaration periodic function instead of reDraw in methods, so that each component will generate its own throttle function when initializing. It should be noted that the arrow function is used for the parameters of the throttle function at this time, because this will point to the component instance.

These are the pits brought to me by throttling function, and now I will share them with you. [Off-duty] [Applause]

The above is the vue component throttle function failure and solution details, more about the vue component throttle function information please pay attention to other related articles on this site!


Related articles: