在实际前端项目中, 会有一些场景 , 在用户点击按钮时 ,因手抖等各种原因多次点击 , 重复提交请求 . 因此 , 通常情况下,会要求前后端均做一些限流/防手抖策略 . 这里简单说一下各前端如何去实施的.
防抖和限流是我们再开发过程中常用的优化性能的方式
通常 , 我们会给重要请求的按钮设置限制 , 比如 500ms 只能提交一次
Android (Java)
Android 中我们使用 RxBinding
来实现 .
添加依赖
build.gradle
1 2
| implementation "com.jakewharton.rxbinding2:rxbinding:${version}"
|
RxBind.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class RxBind {
public static final long THROTTLE_FIRST = 500;
public static Disposable click(View view, Consumer<View> action) { return click(view,action,THROTTLE_FIRST); }
public static Disposable click(View view, Consumer<View> action, long delay){ return clicks(view) .throttleFirst(delay, TimeUnit.MILLISECONDS) .subscribe(action); }
private static Flowable<View> clicks(@NonNull View view){ return Flowable.create(new ViewClickOnSubscribe(view), BackpressureStrategy.ERROR); } }
|
调用
1
| RxBind.click(button, view -> doSomething());
|
这里是使用到了 RxJava
中的 throttleFirst
操作符 , 意为事件流的触发距第一次触发需要间隔500ms才能生效.
iOS (Swift)
iOS (Swift) 中我们通过 RxSwift
来实现
Podfile
1 2 3 4
| # 查找对应版本填入 pod 'RxSwift', '~> ${version}' # 看需求是否要引用此行 pod 'RxCocoa', '~> ${version}'
|
UIButtonExtension.swift
1 2 3 4 5 6 7 8
| extension UIButton { var click: Observable<Void>{ return self.rx.tap .throttle(Config.clickDelay, scheduler: MainScheduler.instance) } }
|
调用
1 2 3 4 5 6
| button .click .subscribe(onNext: { [weak self] in self?.doSomething() }) .disposed(by: dispose)
|
前端(Javascript)
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
|
export const Debounce = (fn, t) => { let delay = t || 500; let timer; console.log(fn) console.log(typeof fn) return function () { let args = arguments; if(timer){ clearTimeout(timer); } timer = setTimeout(() => { timer = null; fn.apply(this, args); }, delay); } };
export const Throttle = (fn, t) => { let last; let timer; let interval = t || 500; return function () { let args = arguments; let now = +new Date(); if (last && now - last < interval) { clearTimeout(timer); timer = setTimeout(() => { last = now; }, interval); } else { last = now; fn.apply(this, args); } } };
|
使用:
1 2 3 4 5 6 7
| methods:{ getAliyunData:Throttle(function(){ ... },1000), }
|
在Vue中使用
首先定义公共js
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 28 29 30 31 32 33 34 35 36 37 38
| export function _debounce(fn, delay) { var delay = delay || 500; var timer; return function () { var th = this; var args = arguments; if (timer) { clearTimeout(timer); } timer = setTimeout(function () { timer = null; fn.apply(th, args); }, delay); }; }
export function _throttle(fn, interval) { var last; var timer; var interval = interval || 500; return function () { var th = this; var args = arguments; var now = +new Date(); if (last && now - last < interval) { clearTimeout(timer); timer = setTimeout(function () { last = now; }, interval); } else { last = now; fn.apply(th, args); } } }
|
引用
1
| import { _debounce } from "@/utils/public";
|
调用
1 2 3 4 5 6
| methods: { changefield: _debounce(function(_type, index, item) { }, 500) }
|
Flutter
pubspec.yaml
调用示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import 'package:rxdart/rxdart.dart';
final _counterSubject = BehaviorSubject<int>();
@override void initState() { super.initState(); _counterSubject.throttleTime(Duration(milliseconds: 500)).listen((int i) { print(i); }); }
RaisedButton( onPressed: () { _counterSubject.add(1); }, child: Text('Test'), )
|
参考链接