背景
在一些计算较为复杂、操作较为耗时或者操作为引起页面重绘的场景,如果事件触发的频率毫无限制,除了带来性能上的负担,还会导致糟糕的用户体验。如:根据输入框输入的内容向服务端查询相关文章,用户多次点击收藏按钮……
实现
防抖(debounce)
就是指触发事件后在
n
秒内函数只能执行一次,如果在n
秒内又触发了事件,则会重新计算函数执行时间。
常用于实时搜索:用户连续输入,等停下来再去触发搜索接口
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;
}
调用:
void onSearch() {}
debounce(onSearch, 1000)();
节流(throttle)
让函数有节制地执行,而不是毫无节制的触发一次就执行一次。什么叫有节制呢?就是在某个时间内只能执行一次。
常用于按钮重复提交
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;
}
调用:
Future<void> onSubmit() async {}
throttle(onSubmit)();
封装方法复用参考
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();
}
}
}
使用
GestureDetector(
onTap: () => CommonUtil.throttle(onTap, durationTime: durationTime)
)
CommonUtil.debounce(searchApi)
原文连接:Dart/Flutter防抖与节流
所有媒体,可在保留署名、
原文连接
的情况下转载,若非则不得使用我方内容。