阅读 606

Flutter入门与实战(七十九):稳住了,别抖!—— 看GetX 的Worker如何防抖

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

前言

在前后端对接过程中,经常会遇到快速重复点击导致重复请求的问题,如果处理不好一方面容易产生垃圾数据,另一方面还增加了很多无谓请求,导致服务器请求数量过多。在 GetX中,针对这种场景提供了一个Worker类以及几个勾子函数来解决这类问题。

场景1:疯狂点击

举个例子,某些购物 App 会提供互动游戏,通过在限定时间内点击的次数来刷红包或优惠券(都是套路😎),这个时候我们会疯狂地点击天上掉下来的红包或者锦鲤,试想如果每次点击都请求后端,那如果是上万人都这么点击,服务器都会被点崩!对于这种情况,GetX 提供了一个 debounce 的勾子函数,这个函数在限定的时间内只会执行一次指定的回调动作:

Worker debounce<T>(
  RxInterface<T> listener,
  WorkerCallback<T> callback, {
  Duration? time,
  Function? onError,
  void Function()? onDone,
  bool? cancelOnError,
});
复制代码

其中 listener 为状态变量,callback 为状态变量 listener 改变时的回调方法,time为限定时间。三个参数构成的结果是在小于time的时间内,如果listener持续在变化的话就不会执行 callback。如果在超过time时间长度内没有变更才会调用一次callback。举个例子,我们一个计数器counter,按如下方式设定:

debounce(_counter, (latestValue) => print("callback: $latestValue"), time: Duration(seconds: 1));
复制代码

然后有一个按钮每点击一次就给计数器的值加1。如果手速够快,我们1秒钟可以点击很多次。这个时候假设我们要防抖,就可以将网络请求放到 callback 里,从而在限定的时间范围内,避免用于的疯狂点击造成过多网络请求,造成类似 DDos 的攻击效果。我们来看一下效果,见下图。

防抖效果

可以看到,我们疯狂点击的时候,回调函数并没有执行,而是停下来间隔一定时间(1秒)才执行。通过这种方式可以减少无谓的请求。这种场景还可以用于搜索场合,当在输入的时候,因为内容在变化,我们不用请求后端数据,而等到用户输入结束之后再请求,这样体验更好而且也能减少后端请求。

场景2:刷金币

在有些场合,我们需要限定一定时间内的请求次数,做类似限流的效果。比如,在点击按钮刷金币的行为,我们可以限制没2秒最多刷1次,这样1分钟内最多只能刷30次,在 GetX 中提供了一个 interval 的方法:

Worker interval<T>(
  RxInterface<T> listener,
  WorkerCallback<T> callback, {
  Duration time = const Duration(seconds: 1),
  dynamic condition = true,
  Function? onError,
  void Function()? onDone,
  bool? cancelOnError,
})
复制代码

使用和 debounce 类似,只是会忽略间隔 time 时间范围内的变化,在状态变量发生变化且每隔 time时间才会调用1次 callback。同时增加了一个 condition(一个返回truefalse 的函数),只有在该函数返回 true 时才会执行 callback(比如必须是 vip 才可以刷金币)。我们以计数器为例看看效果。

class WorkerController extends GetxController {
  final _counter = 0.obs;
  set counter(value) => this._counter.value = value;
  get counter => this._counter.value;

  late Worker worker;
  int coinCount = 0;

  @override
  void onInit() {
    worker = interval(
      _counter,
      (_) {
        coinCount++;
        print("金币数: $coinCount");
      },
      time: Duration(seconds: 2),
      condition: () => coinCount < 10,
    );
    super.onInit();
  }

  @override
  void dispose() {
    worker.dispose();
    super.dispose();
  }
}
复制代码

刷金币

可以看到金币数每隔1秒才会增加1,而且超过10之后就不再增加了。

其他Worker 勾子函数

GetX 还提供了下面三种 Worker 勾子函数,函数的调用和 interval 一样。

  • once:状态变量变化时只执行一次,比如详情页面的刷新只更新一次浏览次数。
  • ever:每次变化都执行,可以用于点赞这种场合
  • everAll:用于列表类型状态变量,只要列表元素改变就会执行回调。

Worker 使用注意事项

为避免Worker 反复被注册,应当在 GetxController的构造方法或 onInit声明周期注册,或者在 StatefulWidgetinitState 中注册(不推荐)。注意的是,需要在 dispose 方法中调用Workerdispose 方法销毁 Worker 对象。

总结

本篇介绍了 GetXWorker 类以及对应的勾子函数的使用,通过注册 Worker 可以用于应用的防抖和限流,从而防止误触发和降低服务器请求数以降低资源消耗。

我是岛上码农,微信公众号同名,这是Flutter 入门与实战的专栏文章,提供体系化的 Flutter 学习文章。对应源码请看这里:Flutter 入门与实战专栏源码。如有问题可以加本人微信交流,微信号:island-coder

👍🏻:觉得有收获请点个赞鼓励一下!

🌟:收藏文章,方便回看哦!

💬:评论交流,互相进步!

文章分类
Android
文章标签