一、前言
浏览器的 resize
、scroll
、keypress
、mousemove
等事件在触发时,会极速地调用绑定在事件上的回调函数,极大地浪费资源,降低前端性能
为了优化体验,需要对这类事件进行调用次数的限制,对此我们可以采用debounce
(防抖)和throttle
(节流)的方式来减少调用频率,同时又不影响实际效果
下面来看一张图:
从上图中,可以看到:
- 防抖是一段时间后只执行一次
- 节流是在固定的频率执行
二、防抖(debounce)
防抖是当连续触发事件的时候,事件不会持续触发,当一定时间内没有触发事件后,事件函数才会执行
例如:就好像在百度搜索时,每次输入之后都有联想词弹出,这个控制联想词的方法就不可能是输入框内容一改变就触发的,它一定是当你结束输入一段时间之后才会触发
下面来举个例子
// 普通方案
let container = document.getElementById('container');
function getUserAction() {
container.innerHTML = count++;
};
container.onmousemove = getUserAction; // 鼠标移动会一直触发getUserAction函数
// 优化后的方案
function debounce(func, wait) {
let timeout;
return function () {
let context = this; // 保存this指向
let args = arguments; // 拿到event对象
clearTimeout(timeout)
timeout = setTimeout(function(){
func.apply(context, args)
}, wait);
}
}
container.onmousemove = debounce(getUserAction, 1000); // 1s内不再触发后才会执行事件
这里作一下分析:
- 在
mousemove
事件上绑定处理函数,这时debounce
函数会立即调用,实际上绑定的函数是debounce
函数内部返回的函数 - 每一次事件被触发,都会清除当前的
timeout
然后重新设置超时调用 - 只有在最后一次触发事件,才能在
wait
时间后执行
我们也可以为 debounce
函数加一个参数,可以选择是否立即执行函数
function debounce(func, wait, immediate) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout); // timeout 不为null
if (immediate) {
let callNow = !timeout; // 第一次会立即执行,以后只有事件执行后才会再次触发
timeout = setTimeout(function(){
timeout = null;
}, wait)
if (callNow) func.apply(context, args)
}
else {
timeout = setTimeout(function(){
func.apply(context, args)
}, wait);
}
}
}
三、节流(throttle)
节流是当持续触发事件时,保证一段时间内,只调用一次事件处理函数
例如:浏览器播放事件,每隔一秒计算一次进度信息。
节流的实现方式可以分为两种:
第一种通过时间戳来实现,用一个变量保存上一次执行的时间,每次触发事件时生成一个时间戳,与上一次执行时间比较,如果大于给定的时间,则执行函数
function throttle(func, wait) {
let context, args;
let previous = 0;
return function() {
let now = +new Date();
context = this;
args = arguments;
if (now - previous > wait) {
func.apply(context, args);
previous = now;
}
}
}
第二种通过定时器来实现,设置一个变量绑定一个定时器,通过if判断定时器是否存在,如果存在就不执行,当定时器执行时把变量置为null,这样在下一次触发事件时就可以设置定时器了
function throttle(func, wait) {
var timeout;
var previous = 0;
return function() {
context = this;
args = arguments;
if (!timeout) {
timeout = setTimeout(function(){
timeout = null;
func.apply(context, args)
}, wait)
}
}
}
比较这两种方法:
- 第一种事件会立刻执行,第二种事件会在 n 秒后第一次执行
- 第一种事件停止触发后没有办法再执行事件,第二种事件停止触发后依然会再执行一次事件
四、区别
防抖和节流的作用都是防止函数多次调用
区别在于,假设一个用户一直触发这个函数,且每次触发函数的间隔小于wait
(参数wait),防抖的情况下只会调用一次,而节流的情况会每隔一定时间调用函数
五、结束语
如果觉得这篇文章对你有帮助,可以伸出你的小手,为这篇文章点个赞
我是前端路上一位新晋的萌新,怀着学习的态度,怀着认识各位同伴的心态,把自己的知识分享出来,除了让自己对知识认知更加巩固,也希望大家能够通过我写的文章学到一点微薄的知识,如果知识内容有误,可以在评论区或者下面公众号告诉我,我会立刻更改
最后,我也创建了一个 【前端收割机】的公众号,希望大家可以关注一波,里面的文章都是掉头发之作
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!