回复
前端面试系列-JavaScript-防抖与节流(用节流优化防抖)
开发者训练营官方
发布于 2021-3-25 17:06
浏览
1收藏
一.函数防抖
当持续触发事件时,并不执行事件处理函数,一定时间段内没有再触发事件,事件处理函数才会执行一次;如果设定的时间到来之前,又一次触发了事件,就重新开始延时。
function debounce(fn, delay) {
// 定时器
let timer = null
// 将debounce处理结果当作函数返回
return function () {
// 保留调用时的this上下文
let context = this
// 保留调用时传入的参数
let args = arguments
// 每次事件被触发时,都去清除之前的旧定时器
if(timer) {
clearTimeout(timer)
}
// 设立新定时器
timer = setTimeout(function () {
fn.apply(context, args)
}, delay)
}
}
二、函数节流
当持续触发事件时,保证一定时间段内只调用一次事件处理函数。
1.时间戳实现
function throttle(fn, interval) {
// last为上一次触发回调的时间
// 对比时间戳,初始化为0则首次触发立即执行,初始化为当前时间戳则wait毫秒后触发才会执行
let last = 0;
// 将throttle处理结果当作函数返回
return function () {
// 保留调用时的this上下文
let context = this
// 保留调用时传入的参数
let args = arguments
// 记录本次触发回调的时间
let now = Date.now();
// 判断上次触发的时间和本次触发的时间差是否小于时间间隔的阈值
if (now - last >= interval) {
// 如果时间间隔大于我们设定的时间间隔阈值,则执行回调
last = now;
fn.apply(context, args);
}
}
}
2.定时器实现
function throttle(fn, wait) {
let timeout;
return function() {
if (!timeout) {
timeout = setTimeout(() => {
timeout = null
fn.call(this, arguments)
}, wait)
}
}
}
3.用节流优化防抖(定时器+时间戳)
防抖的问题在于如果用户的操作十分频繁——他每次都不等 设置的 delay 时间结束就进行下一次操作,于是每次都为该用户重新生成定时器,回调函数被延迟了不计其数次。 频繁的延迟会导致用户迟迟得不到响应,用户同样会产生“这个页面卡死了”的观感。
用节流来优化,保证在一定时间段内会调用一次事件处理函数。
function throttle(fn, delay) {
// last为上一次触发回调的时间, timer是定时器
let last = 0, timer = null
// 将throttle处理结果当作函数返回
return function () {
// 保留调用时的this上下文
let context = this
// 保留调用时传入的参数
let args = arguments
// 记录本次触发回调的时间
let now = +new Date()
// +是一元操作符,利用js隐式转换将其他类型变为数字类型
// 判断上次触发的时间和本次触发的时间差是否小于时间间隔的阈值
if (now - last < delay) {
// 如果时间间隔小于我们设定的时间间隔阈值,则为本次触发操作设立一个新的定时器
clearTimeout(timer)
timer = setTimeout(function () {
last = now
fn.apply(context, args)
}, delay)
} else {
// 如果时间间隔超出了我们设定的时间间隔阈值,那就不等了,无论如何要反馈给用户一次响应
last = now
fn.apply(context, args)
}
}
}
三、总结
函数防抖:将几次操作合并为一此操作进行。原理是维护一个计时器,规定在delay时间后触发函数,但是在delay时间内再次触发的话,就会取消之前的计时器而重新设置。这样一来,只有最后一次操作能被触发。
函数节流:使得一定时间内只触发一次函数。原理是通过判断是否到达一定时间来触发函数。
区别: 函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,而函数防抖只是在最后一次事件后才触发一次函数。
场景:比如在页面的无限加载场景下,我们需要用户在滚动页面时,每隔一段时间发一次 Ajax 请求,而不是在用户停下滚动页面操作时才去请求数据。这样的场景,就适合用节流技术来实现。
四、例子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<h1> JS的节流与防抖</h1>
<body>
</body>
<script>
// JS的节流与防抖
//用节流优化防抖 (定时器+时间戳)
function throttle(fn, delay) {
let last = 0,
timer = null
return function () {
// 保留调用时的this上下文
let context = this
// 保留调用时传入的参数
let args = arguments
// 记录本次触发回调的时间
let now = +new Date()
// +是一元操作符,利用js隐式转换将其他类型变为数字类型
// 判断上次触发的时间和本次触发的时间差是否小于时间间隔的阈值
if (now - last < delay) {
// 如果时间间隔小于我们设定的时间间隔阈值,则为本次触发操作设立一个新的定时器
clearTimeout(timer)
timer = setTimeout(function () {
last = now
fn.apply(context, args)
}, delay)
} else {
// 如果时间间隔超出了我们设定的时间间隔阈值,那就不等了,无论如何要反馈给用户一次响应
last = now
fn.apply(context, args)
}
}
}
// 用新的throttle包装scroll的回调
const better_scroll3 = throttle(() => console.log('防抖+节流,触发了滚动事件'), 1000)
document.addEventListener('scroll', better_scroll3)
</script>
</html>
————————————————
版权声明:本文为博主「LYFlied」的原创文章
分类
赞
1
收藏 1
回复
相关推荐