节流
定义:对于连续触发的函数,规定两次执行间隔时间必须不小于time值才能再次触发
//节流:
function throttle(fn,time){
let start = new Date()
return function(){
let now = new Date()
let time_ = now - start
if(time_>=time){
start = now
return fn.apply(this,arguments)
}
}
}
function fn(){
console.log(123)
}
window.onscroll = throttle(fn,1000)
防抖
定义:对于连续触发的事件,比如window.onresize事件,不必一改变窗口大小就触发事件,可以等到不再改变窗口大小的时候再触发,只执行1次
function fn() {
console.log(123)
}
function debounce(fn,time=500) {
let timer = null
return function () {
//存储调用该函数的对象
let that = this
//如果之前存在定时器,就取消掉
if (timer){
clearTimeout(timer)
}
//改变真正要执行的函数的this
//100毫秒之后,把要执行的函数放到task队列,等到同步代码执行完后,才会把task队列中的哈数放入执行栈中执行
// 不能设为0,不然效果和不防抖差不多
//设置time值为0的话,还没等到下一次执行函数把timer取消掉,fn.bind(that)函数就已经执行了
//设置为0的话,会把fn.bind(that)函数立即放入task队列中,因为没有其他同步代码要执行了,就会立即把task队列中的fn.bind(that)函数放到执行栈执行
timer = setTimeout(fn.bind(that),time)
}
}
window.onscroll = debounce(fn,100)
clearTimeout
let timer = null
function fn(){
console.log(123)
}
timer = setTimeout(fn,0)
console.log(456)
clearTimeout(timer)
结果:只打印456,没有打印123,
分析:即使立即把要执行的函数fn放到task队列中,再执行其他同步代码的时候,也可以取消定时器。
问题:既然设置为0,都能取消定时器,为什么上面的防抖不能设置time为0呢?
因为每次窗口滚动执行函数到这一步,如果time为0的话,就立即把函数放到task队列中,因为又没有其他的同步代码需要执行了,所以就会把task队列中的函数拿到执行栈中立即执行,这样一来,效果就和没有防抖时候一样,还是会多次触发。