背景
在一些计算较为复杂、操作较为耗时或者操作为引起页面重绘的场景,如果事件触发的频率毫无限制,除了带来性能上的负担,还会导致糟糕的用户体验。如:根据输入框输入的内容向服务端查询相关文章,用户多次点击收藏按钮……
实现
防抖(debounce)
就是指触发事件后在
n
秒内函数只能执行一次,如果在n
秒内又触发了事件,则会重新计算函数执行时间。
常用于实时搜索:用户连续输入,等停下来再去触发搜索接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
import 'dart:async'; Map<String, Timer> _funcDebounce = {}; /// 函数防抖 /// [func]: 要执行的方法 /// [milliseconds]: 要迟延的毫秒时间 Function debounce(Function func, [int milliseconds = 500]) { assert(func != null); Function target = () { String key = func.hashCode.toString(); Timer _timer = _funcDebounce[key]; if (_timer == null) { func?.call(); _timer = Timer(Duration(milliseconds: milliseconds), () { Timer t = _funcDebounce.remove(key); t?.cancel(); t = null; }); _funcDebounce[key] = _timer; } }; return target; } |
调用:
1 2 3 |
void onSearch() {} debounce(onSearch, 1000)(); |
节流(throttle)
让函数有节制地执行,而不是毫无节制的触发一次就执行一次。什么叫有节制呢?就是在某个时间内只能执行一次。
常用于按钮重复提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
import 'dart:async'; Map<String, bool> _funcThrottle = {}; /// 函数节流 /// [func]: 要执行的方法 Function throttle(Future Function() func) { if (func == null) { return func; } Function target = () { String key = func.hashCode.toString(); bool _enable = _funcThrottle[key] ?? true; if (_enable) { _funcThrottle[key] = false; func().then((_) { _funcThrottle[key] = false; }).whenComplete(() { _funcThrottle.remove(key); }); } }; return target; } |
调用:
1 2 3 |
Future<void> onSubmit() async {} throttle(onSubmit)(); |
封装方法复用参考
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
class CommonUtil { static const deFaultDurationTime = 300; static Timer timer; // 防抖函数 static debounce(Function doSomething, {durationTime = deFaultDurationTime}) { timer?.cancel(); timer = new Timer(Duration(milliseconds: durationTime), () { doSomething?.call(); timer = null; }); } // 节流函数 static const String deFaultThrottleId = 'DeFaultThrottleId'; static Map<String, int> startTimeMap = {deFaultThrottleId: 0}; static throttle(Function doSomething, {String throttleId = deFaultThrottleId, durationTime = deFaultDurationTime, Function continueClick}) { int currentTime = DateTime.now().millisecondsSinceEpoch; if (currentTime - (startTimeMap[throttleId] ?? 0) > durationTime) { doSomething?.call(); startTimeMap[throttleId] = DateTime.now().millisecondsSinceEpoch; } else { continueClick?.call(); } } } |
使用
1 2 3 4 5 |
GestureDetector( onTap: () => CommonUtil.throttle(onTap, durationTime: durationTime) ) CommonUtil.debounce(searchApi) |
原文连接:Dart/Flutter防抖与节流
所有媒体,可在保留署名、
原文连接
的情况下转载,若非则不得使用我方内容。