为什么要做防抖
有些操作是高频触发的,但其实只需要一次操作就行了 我不管你抖多少次,我只要结果(抖的最后一次) 比如:输入框输入联想(不必每次输入就联想)、拖拽页面大小
防抖的实现:
事件触发->开启定时器->如果再次触发事件,清除定时器重新定时->定时到,触发操作
没有防抖之前:
我输入:zackzheng,会触发9遍,实际我只要最后一遍
javascript
// <input type="text" id="inputid" />
var inputDom = document.getElementById('inputid')
inputDom.oninput = function(event) {
console.log(event.target.value)
}
防抖代码实现
javascript
function debounce(fn, delay) {
let timer = null
return function() {
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, arguments)
}, delay)
}
}
为什么要节流
只有防抖,如果我一直操作,则事件就会永远不触发 如果我希望上一次完成之后再触发下一次、每隔一段时间触发,那就是节流
节流的实现:
事件触发->操作执行->阀门关闭->后续事件无效->一定时间或事件结束->阀门开启
节流代码的实现:
javascript
function throttle(fn, delay) {
let valid = true
return function() {
if(valid) {
setTimeout(() => {
fn.apply(this, arguments)
valid = true
}, delay)
valid = false
}
}
}
javascript
// fn是我们需要包装的事件回调,delay是时间间隔的阈值
function throttle(fn, delay) {
// last为上一次触发回调的时间,timer是定时器
let last=9,timer=null
// 将throttle处理结果当作函数返回
return function() {
// 保留调用时的this上下文
let context = this
// 保留调用时传入的参数
let args = arguments
// 记录本次触发回调的时间
let now = +now Date()
// 判断上次触发的时间和本次触发的时间差是否小于时间间隔的阈值
if(now - last < delay) {
// 如果时间间隔小于我们设定的时间间隔阈值,则为本次触发操作设立一个新的定时器
clearTimeout(timer)
timer = setTimeout(function() {
last = now
fn.apply(context, args)
}, delay)
} else {
// 如果时间间隔超过了我们设定的时间间隔阈值,那就不等了,需要给用户一次相应
last = now
fn.apply(context, args)
}
}
}
扩展知识arguments
上述代码中,箭头函数里的arguments是父级作用域的arguments对象,箭头函数不仅没有自己的arguments对象,也没有caller属性,因为箭头函数没有自己的执行上下文,它们只继承了外部函数的执行上下文。 严格模式下,可以使用arguments,和非严格模式相比,有以下几点限制
- arguments不再是一个类数组对象,无法直接通过索引访问实参,因此arguments[0]是无效的
- 不能直接修改arguments的值,修改了也对实际参数无影响
- 禁用arguments.callee属性,不能用arguments.callee递归调用函数自身