防抖和节流
使用场景
有时,我们会绑定一些持续触发的事件,如:resize、scroll、mousemove等,但是我们并不希望在事件持续触发的过程中那么频繁的去执行函数。通常情况下怎么去解决呢?一般来讲,防抖和节流是比较好的解决方案。
下面,我就已在vue中的input函数为例,讲解一下防抖和节流。
防抖
所谓防抖,就是指触发事件后在n秒内,函数只能执行一次,如果在n秒内又触发了事件,则会重新计算函数执行的时间。
其实防抖函数并不难写,下面这就是一个最初级的防抖函数:
<template> <div id="app"> <el-input @input.native="inputFn" v-model='msg'></el-input> </div> </template> <script> export default { components: {}, data(){ return{ msg: '', timeout: '' } }, methods: { // 最初级的防抖 inputFn(e){ if(this.timeout) clearTimeout(this.timeout) this.timeout = setTimeout(() => { console.log('执行函数') }, 3000) } } } </script>
接下来,我们利用闭包改造一下这个防抖函数,不要将timeout定义在函数外面了
<template> <div id="app"> <el-input @input.native="inputFn" v-model='msg'></el-input> </div> </template> <script> export default { components: {}, data(){ return{ msg: '', timeout: '', delay: '' } }, mounted(){ // 初始化防抖函数 this.delay = this.debounceFun(this.requestFun, 3000) }, methods: { inputFn(e){ this.delay('传入的参数') }, // 第二版,非立即执行 // 非立即执行版的意思是触发事件后函数不会立即执行,而是在 n 秒后执行,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。 debounceFun(func, wait){ let timeout = '' return function(){ let context = this let args = arguments if(timeout) clearTimeout(timeout) timeout = setTimeout(() => { func.apply(context, args) }, wait) } }, requestFun(data){ console.log(data) console.log('执行函数') } } } </script>
这样,我们就把防抖函数写好了,是不是很简单
这面的这种是非立即执行版的,下面我们再来改造一下,实现一版立即执行版的防抖函数
立即执行版的意思是触发事件后函数会立即执行,然后 n 秒内不触发事件才能继续执行函数的效果。
// 第三版:立即执行 // 立即执行版的意思是触发事件后函数会立即执行,然后 n 秒内不触发事件才能继续执行函数的效果。 debounceFun(func, wait){ let timeout = '' return function(){ let context = this let args = arguments // 记录当前是否存在timeout,如果不存在,则说明是第一次 let isNow = !timeout if(timeout) clearTimeout(timeout) timeout = setTimeout(() => { func.apply(context, args) }, wait) // 如果不存在timeout,说明是第一次触发,则执行一次回调函数 if(isNow) func.apply(context, args) } }
下面,我们再来写一版立即执行和非立即执行的合并版
// 第四版 // 当immediate为true时,是立即执行版;当immediate为false时,是非立即执行版 debounceFun(func, wait, immediate){ let timeout = '' return function(){ let context = this let args = arguments // 记录当前是否存在timeout,如果不存在,则说明是第一次 let firstFlag = !timeout if(timeout) clearTimeout(timeout) timeout = setTimeout(() => { func.apply(context, args) }, wait) if(immediate){ // 如果不存在timeout,说明是第一次触发,则执行一次回调函数 firstFlag && func.apply(context, args) } } }
节流
所谓节流,就是指连续触发事件,但是在n秒钟只执行一次的函数。节流会稀释函数的执行频率
throttleFun(func, wait){ let timeout = '' return function(){ let context = this let args = arguments if(!timeout){ timeout = setTimeout(() => { timeout = null func.apply(context, args) }, wait) } } }