返回

巧用防抖与节流:优雅化解微信小程序wx.request请求偶发重复调用

前端

在我们愉快地开发项目时,偶发性地总是能够遇到这么一个问题:由于用户多次连续点击(偶尔网络延迟也会导致连续请求),或者是不合时宜的重复请求,导致我们希望在客户端进行了一次请求,但实际会触发很多次,从而可能造成服务器端的无效请求处理、数据错误等等问题。

浅谈防抖与节流:

防抖与节流都是用来优化函数执行频率的两种常用技术。防抖在连续触发时,只执行最后一次触发,而节流则会在一段时间内只执行一次触发。
换句话来说,防抖适用于保证最低的触发频率,节流适合于保证最高触发频率。

实现防抖与节流有两种方法:实现包装函数和直接实现。

实现包装函数:

我们先聊聊实现包装函数的方法。对于直接使用函数调用时,使用装饰器添加功能是很合适的方法,然而在微信小程序里,我们得不到直接修改执行环境的方法。让我们看看防抖和节流在装饰器的实现:

  1. 防抖实现:
/**
 * 防抖函数:
 * 在一段时间内,多次触发后只执行最后一次
 */
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);
  };
}
  1. 节流实现:
/**
 * 节流函数:
 * 在一段时间内,只执行一次
 */
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; // 更新上一次执行的时间戳
    }
  };
}

使用防抖和节流函数时,我们只需要传入函数和延迟时间,就可以实现对函数执行频率的优化。

直接实现:

现在,我们来聊聊如何直接实现防抖和节流。

  1. 防抖实现:
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);
  }
}
  1. 节流实现:
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);

这里使用节流函数的优点是,当用户在短时间内多次下拉刷新时,只会有第一次下拉刷新触发请求。

结语:

防抖和节流是两个非常有用的函数,它们可以用来优化函数执行的频率,减少不必要的请求,从而提高小程序的性能和用户体验。我们可以根据实际场景选择使用防抖还是节流,来实现最佳的性能优化。