debounce,throttle in dart , 参考 lodash , 拷贝 rate_limiter 库

434 阅读1分钟

image.png

Debounce

import 'dart:async' show Timer;
import 'dart:math' as math;

const _undefined = Object();

class Debounce {
  Debounce(
    this._func,
    Duration wait, {
    bool leading = false,
    bool trailing = true,
    Duration? maxWait,
  })  : _leading = leading,
        _trailing = trailing,
        _wait = wait.inMilliseconds,
        _maxing = maxWait != null {
    if (_maxing) {
      _maxWait = math.max(maxWait!.inMilliseconds, _wait);
    }
  }

  final Function _func;
  final bool _leading;
  final bool _trailing;
  final int _wait;
  final bool _maxing;

  int? _maxWait;
  Object? _lastArgs = _undefined;
  Object? _lastNamedArgs = _undefined;
  Timer? _timer;
  int? _lastCallTime;
  Object? _result;
  int _lastInvokeTime = 0;

  Object? _invokeFunc(int time) {
    final args = _lastArgs as List<Object?>?;
    final namedArgs = _lastNamedArgs as Map<Symbol, Object?>?;
    _lastInvokeTime = time;
    _lastArgs = _lastNamedArgs = _undefined;
    return _result = Function.apply(_func, args, namedArgs);
  }

  Timer _startTimer(Function pendingFunc, int wait) =>
      Timer(Duration(milliseconds: wait), () => pendingFunc());

  bool _shouldInvoke(int time) {
    if (_lastCallTime == null) return true;

    final timeSinceLastCall = time - _lastCallTime!;
    final timeSinceLastInvoke = time - _lastInvokeTime;

    return (timeSinceLastCall >= _wait) ||
        (timeSinceLastCall < 0) ||
        (_maxing && timeSinceLastInvoke >= _maxWait!);
  }

  Object? _trailingEdge(int time) {
    _timer = null;

    if (_trailing &&
        (_lastArgs != _undefined || _lastNamedArgs != _undefined)) {
      return _invokeFunc(time);
    }
    _lastArgs = _lastNamedArgs = _undefined;
    return _result;
  }

  int _remainingWait(int time) {
    final timeSinceLastCall = time - _lastCallTime!;
    final timeSinceLastInvoke = time - _lastInvokeTime;
    final timeWaiting = _wait - timeSinceLastCall;

    return _maxing
        ? math.min(timeWaiting, _maxWait! - timeSinceLastInvoke)
        : timeWaiting;
  }

  void _timerExpired() {
    final time = DateTime.now().millisecondsSinceEpoch;
    if (_shouldInvoke(time)) {
      _trailingEdge(time);
    } else {
      _timer = _startTimer(_timerExpired, _remainingWait(time));
    }
  }

  Object? _leadingEdge(int time) {
    _lastInvokeTime = time;

    _timer = _startTimer(_timerExpired, _wait);

    return _leading ? _invokeFunc(time) : _result;
  }

  void cancel() {
    _timer?.cancel();
    _lastInvokeTime = 0;
    _lastCallTime = _timer = null;
    _lastArgs = _lastNamedArgs = _undefined;
  }

  Object? flush() {
    final now = DateTime.now().millisecondsSinceEpoch;
    return _timer == null ? _result : _trailingEdge(now);
  }

  bool get isPending => _timer != null;

  Object? call([List<Object?>? args, Map<Symbol, Object?>? namedArgs]) {
    final time = DateTime.now().millisecondsSinceEpoch;
    final isInvoking = _shouldInvoke(time);

    _lastArgs = args;
    _lastNamedArgs = namedArgs;
    _lastCallTime = time;

    if (isInvoking) {
      if (_timer == null) {
        return _leadingEdge(_lastCallTime!);
      }
      if (_maxing) {
        _timer = _startTimer(_timerExpired, _wait);
        return _invokeFunc(_lastCallTime!);
      }
    }
    _timer ??= _startTimer(_timerExpired, _wait);
    return _result;
  }
}

Throttle

import "./debounce.dart";

class Throttle {
  Throttle(
    Function func,
    Duration wait, {
    bool leading = true,
    bool trailing = true,
  }) : _debounce = Debounce(
          func,
          wait,
          leading: leading,
          trailing: trailing,
          maxWait: wait,
        );

  final Debounce _debounce;

  void cancel() => _debounce.cancel();

  Object? flush() => _debounce.flush();

  bool get isPending => _debounce.isPending;

  Object? call(List<Object?> args, [Map<Symbol, Object?>? namedArgs]) {
    return _debounce.call(args, namedArgs);
  }
}

extension DebounceThrottle on Function

import "./debounce.dart";
import "./throttle.dart";

extension DebounceThrottle on Function {
  Debounce debounce(
    Duration wait, {
    bool leading = false,
    bool trailing = true,
    Duration? maxWait,
  }) {
    return Debounce(
      this,
      wait,
      leading: leading,
      trailing: trailing,
      maxWait: maxWait,
    );
  }

  Throttle throttle(
    Duration wait, {
    bool leading = true,
    bool trailing = true,
  }) {
    return Throttle(
      this,
      wait,
      leading: leading,
      trailing: trailing,
    );
  }
}

Debounce debounce(
  Function func,
  Duration wait, {
  bool leading = false,
  bool trailing = true,
  Duration? maxWait,
}) =>
    Debounce(
      func,
      wait,
      leading: leading,
      trailing: trailing,
      maxWait: maxWait,
    );

Throttle throttle(
  Function func,
  Duration wait, {
  bool leading = true,
  bool trailing = true,
}) =>
    Throttle(func, wait, leading: leading, trailing: trailing);

什么是function call / dart
lodash.com/docs/4.17.1…
pub.dev/packages/ra…