出现原因
某些事件,如mousemove、scroll等是会不断触发,如果对应处理函数中有执行DOM操作、加载资源的行为,那很有可能会导致浏览器卡顿、崩溃等
目前主流的解决方法为函数节流与函数防抖
函数节流
思想
当调用动作过n毫秒后,才会执行该动作,若在这n毫秒内又调用此动作则将重新计算执行时
操作
1.第一次调用函数,创建一个定时器,在指定的时间间隔之后运行代码
2.当第二次调用该函数时,清除前一次的定时器并重新设置
3.如果前一个定时器已经执行过了,清除操作并不会产生什么影响
4.如果前一个定时器尚未执行,上述操作就是将其替换为一个新的定时器
method参数为实际执行的函数
args为要传递的参数数组
contex参数为执行环境 */
function throttle(method,args,context){
clearTimeout(method.tId);
method.tId=setTimeout(function(){
method.apply(context,args);
},200);
}
function move(){
console.log("xxx")
}
document.querySelector("#target").οnmοusemοve=function(){
throttle(move);
}
如果我们不进行节流,那么鼠标在target元素上做一次滑行就会执行多次move函数,而节流后move函数执行数量明显变少
VUE中使用:
<template> <div> <input type='text' v-model='value' @keydown = "hangleChange"> </div> </template> <script> function debounce(func, wait=1000){ //可以放入项目中的公共方法中进行调用(鹅只是省事) let timeout; return function(event){ clearTimeout(timeout) timeout = setTimeout(()=>{ func.call(this, event) },wait) } } export default{ name:'', data(){ return{ value:'' } }, methods:{ hangleChange:debounce(function(e){ console.log(this.value) }) } } </script>
局限
如果鼠标一直滑动,那么move方法永远不会执行,这时候就需要函数防抖
函数防抖
思想
预先设定一个执行周期,当调用动作的时刻大于等于执行周期则执行该动作,在这段事件内新的调用动作都将无效,然后进入下一个新周期
/* 一个封装节流操作的函数
method参数为实际执行的函数
wait参数为时间间隔
args为要传递的参数数组
contex参数为执行环境 */
function debounce(method,wait,args,context){
if(!method.start){
method.start=new Date();
}
var now=new Date();
if(now-method.start>=wait){
method.apply(context,args);
method.start=now;
}
}
document.querySelector("#target").οnmοusemοve=function(){
debounce(move,2000);
}
采用函数防抖后,只要鼠标在target上滑动,每2秒执行一次move函数
VUE中使用
<template> <div class="scroll" ref="previewText" @scroll.passive="fnScroll"> </template> <script> export default{ name:'globalHospot', data(){ return{ count:0, fnScroll:() =>{} } }, methods: { fnHandleScroll (e) { console.log('scroll触发了:' + this.count++, new Date()) }, fnThrottle(fn, delay, atleast){ //节流函数 let timer = null; let previous = null; return function(){ let now = +new Date() if(!previous) previous = now; if(atleast && now - previous > atleast){ fn(); previous = now; clearTimeout(timer) }else{ clearTimeout(timer) timer = setTimeout(()=>{ fn(); previous = null },delay) } } } }, created(){ this.fnScroll = this.fnThrottle(this.fnHandleScroll, 1000) //刚创建时执行 }, } </script>