函数防抖是指对于在事件被触发n秒后再执行的回调,若是在这n秒内又从新被触发,则从新开始计时,是常见的优化,适用于闭包
等状况,防止函数过于频繁的没必要要的调用。app
用 setTimeout
实现计时,配合 clearTimeout
实现“从新开始计时”。函数
即只要触发,就会清除上一个计时器,又注册新的一个计时器。直到中止触发 wait 时间后,才会执行回调函数。性能
不断触发事件,就会不断重复这个过程,达到防止目标函数过于频繁的调用的目的。优化
function debounce(func, wait) { let timeout return function () { clearTimeout(timeout) timeout = setTimeout(func, wait) //返回计时器 ID } }
container.onmousemove = debounce(doSomething, 1000);
每当事件被触发,执行的都是那个被返回的闭包函数。this
由于闭包带来的其做用域链中引用的上层函数变量声明周期延长的效果,debounce
函数的 settimeout计时器 ID timeout
变量能够在debounce
函数执行结束后依然留存在内存中,供闭包使用。spa
相比于未防抖时的code
container.onmousemove = doSomething
防抖优化后,指向 HTMLDivElement
的从 doSomething
函数的 this
变成了闭包匿名函数的 this
,前者变成了指向全局变量。
同理,doSomething
函数参数也接收不到 MouseEvent
事件了。对象
function debounce(func, wait) { let timeout return function () { let context = this //传给目标函数 clearTimeout(timeout) timeout = setTimeout( ()=>{func.apply(context, arguments)} //修复 , wait) } }
相比于 一个周期内最后一次触发后,等待必定时间再执行目标函数;blog
咱们有时候但愿能实现 在一个周期内第一次触发,就当即执行一次,而后必定时间段内都不能再执行目标函数。
这样,在限制函数频繁执行的同时,能够减小用户等待反馈的时间,提高用户体验。
在原来基础上,添加一个是否当即执行的功能
function debounce(func, wait, immediate) { let time let debounced = function() { let context = this if(time) clearTimeout(time) if(immediate) { let callNow = !time if(callNow) func.apply(context, arguments) time = setTimeout( ()=>{time = null} //见注解 , wait) } else { time = setTimeout( ()=>{func.apply(context, arguments)} , wait) } } return debounced }
把保存计时器 ID 的 time
值设置为 null
有两个做用:
callNow
为 true
,目标函数能够在新的周期里被触发时被执行timeout
做为闭包引用的上层函数的变量,是不会自动回收的。手动将其设置为 null ,让它脱离执行环境,一边垃圾收集器下次运行是将其回收。添加一个取消当即执行的功能。
函数也是对象,也能够为其添加属性。
为了添加 “取消当即执行”功能,为 debounced 函数添加了个 cancel 属性,属性值是一个函数
debounced.cancel = function() { clearTimeout(time) time = null }
var setSomething = debounce(doSomething, 1000, true) container.onmousemove = setSomething document.getElementById("button").addEventListener('click', function(){ setSomething.cancel() })
function debounce(func, wait, immediate) { let time let debounced = function() { let context = this if(time) clearTimeout(time) if(immediate) { let callNow = !time if(callNow) func.apply(context, arguments) time = setTimeout( ()=>{time = null} //见注解 , wait) } else { time = setTimeout( ()=>{func.apply(context, arguments)} , wait) } } debounced.cancel = function() { clearTimeout(time) time = null } return debounced }
首先在公共函数文件中注册debounce
export function debounce(func, delay) { let timer return function (...args) { if (timer) { clearTimeout(timer) } timer = setTimeout(() => { func.apply(this, args) }, delay) } }
而后在须要使用的组件中引入debounce,而且在created生命周期内调用:
created() { this.$watch('searchText', debounce((newSearchText) => { this.getDatas(newSearchText) }, 200)) }
节流:
一个函数执行一次后,只有大于设定的执行周期,才会执行第二次
//节流函数 function throttle(fn, delay) { //记录上一次函数触发的时间 var lastTime = 0; console.log(this) return function () { //记录当前函数触发的时间 var nowTime = Date.now(); if (nowTime - lastTime > delay) { //修正this的指向 fn.call(this); console.log(this); lastTime = nowTime; } } } document.onscroll = throttle(function () { console.log('触发了scroll' + Date.now()) }, 200)
防抖:
有个须要频繁触发函数,出于优化性能角度,在规定的时间内,只让函数触发的第一次生效,后面的不生效。
function debounce(fn,delay) { //记录上一次的延时器 var timer = null; return function () { clearTimeout(timer); timer = setTimeout(() => { fn.apply(this); }, delay); } }