![114a7463d361bbedce109bd99b525561.png](https://i-blog.csdnimg.cn/blog_migrate/62c8f6a63df49459c3ab8fff9c6a36f3.jpeg)
在前端开发当中,我们都知道有些交互事件,会频繁触发。这样会导致我们的页面渲染性能,如果频繁触发接口调用的话,会直接导致服务器性能的浪费。话不多说,盘它!
![5d2ee6bc7fcb92400490c24b1247226f.png](https://i-blog.csdnimg.cn/blog_migrate/9b81d58511b3bd8c5cc8d895067e4281.jpeg)
我们先简单列一下
onresize onmousemove onkeydown srcoll onkeyup
这里我是用键盘事件 keyup作为测试
我们先看一段测试用例
<ul>
<li>
未做处理:<input type="text" id="ipt">
<div>函数被调用:<span id="count">0</span>次</div>
</li>
</ul>
const oCount = document.getElementById('count');
const oIpt = document.getElementById('ipt');
let init = 0
oIpt.onkeyup = function() {
oCount.innerText = ++init
}
看一下输入时候的运行效果。
![73b102d8b38560978ed35bf887ef1e0d.gif](https://i-blog.csdnimg.cn/blog_migrate/fbd2a90b6a0cab71219fde15e7fdfec3.gif)
我们不难发现,每次输入都会触发事件的执行。如果我们用这样的方式去检测:当前用户输入的用户名是否可用?如此高频率的触发不仅是极大的浪费,而且用户还没有输入完成就检测,对用户的提示也不好。应该等用户输入完了,我们再去触发函数,下面我们优化一下:
// 设置一个默认值 300ms
const oCount2 = document.getElementById('count2');
const oIpt2 = document.getElementById('ipt2');
// 设置一个默认值 300ms
const debounce = (fn, wait = 300) => {
let time = null
return function(arguments) {
const _this = this, args = arguments
clearTimeout(time)
time = setTimeout(() => {
fn.apply(_this, [args])
// fn.call(_this, args) //或者使用这个
}, wait)
}
}
let init2 = 0
oIpt2.onkeyup = debounce(function() {
oCount2.innerText = ++init2
}, 500) //可以自己定义延迟时间间隔
再来看一下比对效果:
![3ebb28b80b8cfe47a32d14dd4f176998.gif](https://i-blog.csdnimg.cn/blog_migrate/5895bf9a200e2cc3ba4a92a349f73112.gif)
可以看到,加了防抖函数之后,当我们在频繁输入的时候,函数并没有执行, 只有在函数指定的间隔内(500ms)不再输入了,才会执行函数。如果在时间间隔之内继续输入,会触发函数重新计数。
函数防抖的概念:在事件触发后的n秒之后,再去执行真正需要执行的函数,如果在这n秒之内事件又被触发,则重新开始计时
也就是说,如果用户在间隔时间内一直触发函数,那么这个防抖函数内部的真正需要执行的函数将永远无法执行。
那有没有什么好点的办法,让用户在输入过程中,既能触发真实需要的函数,又能达到优化的效果?答案是肯定的,那就是:
函数截流
事例代码如下
const oCount3 = document.getElementById('count3');
const oIpt3 = document.getElementById('ipt3');
const oTime = document.getElementById('time');
const throttle = (fn, threshhold = 1000) => {
let last, deferTimer
return function(arguments) {
const _this = this, args = arguments
let now = +new Date()
if(last && now < last + threshhold) {
clearTimeout(deferTimer)
deferTimer = setTimeout(function () {
last = now
fn.call(_this, args)
}, threshhold)
} else {
last = now
fn.call(_this, args)
}
}
}
let init3 = 0
const throttleIpt = throttle(function() {
let time = new Date().getMinutes() + ':' + new Date().getSeconds()
oTime.innerText = time
oCount3.innerText = ++init3
}, 1000) // 初始化一下
oIpt3.onkeyup = function() {
throttleIpt()
}
由于我们设置的时间间隔是1000ms也就是1s。我来看一下优化效果:(注意看调用次数和时间上秒的变化)
![021bc400ce405e9c85442ade640d1639.gif](https://i-blog.csdnimg.cn/blog_migrate/571329715dab7a096e6a24e83364279e.gif)
可以看到,任由我们怎么输入,函数会按照我们设定的时间(1s),每秒执行一次。你可以设置更大。
函数截流的概念:规定好一个单位时间,触发函数一次。如果在这个单位时间内触发多次函数的话,只有一次是可被执行的。想执行多次的话,只能等到下一个周期里
他们之间的优缺点,等我下次总结吧!
下面 的你值得拥有:
沈志勇说