写点什么

稳住了,别抖!—— 看 GetX 的 Worker 如何防抖

作者:岛上码农
  • 2022 年 6 月 20 日
  • 本文字数:1783 字

    阅读完需:约 6 分钟

稳住了,别抖!—— 看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 可以用于应用的防抖和限流,从而防止误触发和降低服务器请求数以降低资源消耗。


发布于: 刚刚阅读数: 3
用户头像

岛上码农

关注

用代码连接孤岛,公众号@岛上码农 2022.03.03 加入

从南漂到北,从北漂到南的业余码农

评论

发布
暂无评论
稳住了,别抖!—— 看GetX 的Worker如何防抖_flutter_岛上码农_InfoQ写作社区