巧用防抖与节流:优雅化解微信小程序wx.request请求偶发重复调用
2024-01-29 12:11:19
在我们愉快地开发项目时,偶发性地总是能够遇到这么一个问题:由于用户多次连续点击(偶尔网络延迟也会导致连续请求),或者是不合时宜的重复请求,导致我们希望在客户端进行了一次请求,但实际会触发很多次,从而可能造成服务器端的无效请求处理、数据错误等等问题。
浅谈防抖与节流:
防抖与节流都是用来优化函数执行频率的两种常用技术。防抖在连续触发时,只执行最后一次触发,而节流则会在一段时间内只执行一次触发。
换句话来说,防抖适用于保证最低的触发频率,节流适合于保证最高触发频率。
实现防抖与节流有两种方法:实现包装函数和直接实现。
实现包装函数:
我们先聊聊实现包装函数的方法。对于直接使用函数调用时,使用装饰器添加功能是很合适的方法,然而在微信小程序里,我们得不到直接修改执行环境的方法。让我们看看防抖和节流在装饰器的实现:
- 防抖实现:
/**
* 防抖函数:
* 在一段时间内,多次触发后只执行最后一次
*/
function debounce(func, wait) {
let timeout = null; // 缓存定时器
return function () {
const context = this; // 保存当前上下文
const args = arguments; // 保存参数
// 取消上一次执行的定时器,避免重复调用
clearTimeout(timeout);
// 在 wait 毫秒后执行函数
timeout = setTimeout(() => {
func.apply(context, args);
}, wait);
};
}
- 节流实现:
/**
* 节流函数:
* 在一段时间内,只执行一次
*/
function throttle(func, wait) {
let lastCallTime = 0; // 上一次执行的时间戳
return function () {
const context = this; // 保存当前上下文
const args = arguments; // 保存参数
const now = Date.now(); // 获取当前时间戳
// 如果距离上次执行的时间已经超过 wait 毫秒,则立即执行函数
if (now - lastCallTime > wait) {
func.apply(context, args);
lastCallTime = now; // 更新上一次执行的时间戳
}
};
}
使用防抖和节流函数时,我们只需要传入函数和延迟时间,就可以实现对函数执行频率的优化。
直接实现:
现在,我们来聊聊如何直接实现防抖和节流。
- 防抖实现:
class Debounce {
constructor(func, wait) {
this.func = func;
this.wait = wait;
this.timeout = null; // 缓存定时器
}
debounce() {
const context = this; // 保存当前上下文
const args = arguments; // 保存参数
// 取消上一次执行的定时器,避免重复调用
clearTimeout(this.timeout);
// 在 wait 毫秒后执行函数
this.timeout = setTimeout(() => {
this.func.apply(context, args);
}, this.wait);
}
}
- 节流实现:
class Throttle {
constructor(func, wait) {
this.func = func;
this.wait = wait;
this.lastCallTime = 0; // 上一次执行的时间戳
}
throttle() {
const context = this; // 保存当前上下文
const args = arguments; // 保存参数
const now = Date.now(); // 获取当前时间戳
// 如果距离上次执行的时间已经超过 wait 毫秒,则立即执行函数
if (now - this.lastCallTime > this.wait) {
this.func.apply(context, args);
this.lastCallTime = now; // 更新上一次执行的时间戳
}
}
}
使用防抖和节流类时,我们需要先创建实例,然后在需要使用时调用实例的方法。
微信小程序应用:
在微信小程序中,我们可以使用防抖和节流来优化 wx.request 请求。例如,我们在页面中有一个按钮,当用户点击按钮时,会触发一个函数发送请求。为了防止用户多次连续点击按钮导致重复请求,我们可以使用防抖来优化这个函数。
const myButton = document.getElementById('my-button');
const debounceRequest = debounce((e) => {
// 发送请求
}, 500); // 500 毫秒的延迟
myButton.addEventListener('click', debounceRequest);
这种情况下,使用防抖函数的优点是,当用户连续点击按钮时,只会有最后一次点击触发请求。
又或者,我们在页面中有一个下拉刷新组件,当用户下拉刷新时,会触发一个函数发送请求。为了防止用户在短时间内多次下拉刷新导致重复请求,我们可以使用节流来优化这个函数。
const myRefreshControl = document.getElementById('my-refresh-control');
const throttleRequest = throttle((e) => {
// 发送请求
}, 1000); // 1000 毫秒的延迟
myRefreshControl.addEventListener('pulldownrefresh', throttleRequest);
这里使用节流函数的优点是,当用户在短时间内多次下拉刷新时,只会有第一次下拉刷新触发请求。
结语:
防抖和节流是两个非常有用的函数,它们可以用来优化函数执行的频率,减少不必要的请求,从而提高小程序的性能和用户体验。我们可以根据实际场景选择使用防抖还是节流,来实现最佳的性能优化。