转载

大前端常用按钮限流防抖总结

在实际前端项目中, 会有一些场景 , 在用户点击按钮时 ,因手抖等各种原因多次点击 , 重复提交请求 . 因此 , 通常情况下,会要求前后端均做一些限流/防手抖策略 . 这里简单说一下各前端如何去实施的.

防抖和限流是我们再开发过程中常用的优化性能的方式

通常 , 我们会给重要请求的按钮设置限制 , 比如 500ms 只能提交一次

Android (Java)

Android 中我们使用 RxBinding 来实现 .

添加依赖

build.gradle

// 查找对应版本填入
implementation "com.jakewharton.rxbinding2:rxbinding:${version}"

RxBind.java

public class RxBind {

    // 默认按钮防手抖时间(ms)
    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);
    }
}

调用

RxBind.click(button, view -> doSomething());

这里是使用到了 RxJava 中的 throttleFirst 操作符 , 意为事件流的触发距第一次触发需要间隔500ms才能生效.

iOS (Swift)

iOS (Swift) 中我们通过 RxSwift 来实现

Podfile

# 查找对应版本填入
pod 'RxSwift',    '~> ${version}'
# 看需求是否要引用此行
pod 'RxCocoa',    '~> ${version}'

UIButtonExtension.swift

extension UIButton {
    
    /// 防重复提交
    var click: Observable<Void>{
        return self.rx.tap
        .throttle(Config.clickDelay, scheduler: MainScheduler.instance)
    }
}

调用

button
         .click
         .subscribe(onNext: { [weak self] in
             self?.doSomething()
         })
         .disposed(by: dispose)

前端(Javascript)

/**
 * 函数防抖 (只执行最后一次点击)
 * @param fn
 * @param delay
 * @returns {Function}
 * @constructor
 */
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);
    }
};
 
 
/**
 * 函数节流
 * @param fn
 * @param interval
 * @returns {Function}
 * @constructor
 */
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;
                fn.apply(this, args);
            }, interval);
        } else {
            last = now;
            fn.apply(this, args);
        }
    }
};

使用:

 
methods:{
	getAliyunData:Throttle(function(){
	...
	 },1000),
}

在Vue中使用

首先定义公共js

// 防抖
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;
                fn.apply(th, args);
            }, interval);
        } else {
            last = now;
            fn.apply(th, args);
        }
    }
}

引用

import { _debounce } from "@/utils/public";

调用

methods: {
  // 改变场数
  changefield: _debounce(function(_type, index, item) {
      // do something ...
  }, 500)
}

Flutter

pubspec.yaml

rxdart: ^0.22.2

调用示例

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'),
)

参考链接

  • vue 中使用防抖和节流,防止重复点击或重复上拉加载
  • Flutter: debounce 避免高频率事件
原文  https://lhalcyon.com/frontend-throttling/
正文到此结束
Loading...