Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
qqzhao committed Dec 5, 2019
1 parent ec6fe26 commit a6ff3be
Show file tree
Hide file tree
Showing 4 changed files with 228 additions and 3 deletions.
125 changes: 125 additions & 0 deletions lib/flow_control.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import 'dart:async';

void _print(message) {
// print('Throttle debug: $message');
}

//DateTime _lastDateTime;
//
//enum ThrottleAction {
// cancel,
// operate,
//}
//
///// 自己实现的,只能满足没有参数的情况,并且只允许一个block(加Map存储可满足多个).
//throttle(callback, {Duration duration = const Duration(milliseconds: 200), ThrottleAction action = ThrottleAction.cancel}) {
// _print('callback.hash = ${callback.hashCode}');
// if (_lastDateTime == null) {
// _lastDateTime = DateTime.now();
// callback();
// } else {
// int dis = duration.inMilliseconds;
//
// /// 超过了延迟,需要执行一次
// if (DateTime.now().millisecondsSinceEpoch < _lastDateTime.millisecondsSinceEpoch + dis) {
// if (action == ThrottleAction.cancel) {
// _print('ignore action');
// } else {
// // TODO:
// }
// } else {
// _lastDateTime = DateTime.now();
// callback();
// }
// }
//}

Map<Function, _ActionTarget> _throttled = <Function, _ActionTarget>{};
Map<Function, Timer> _debounced = <Function, Timer>{};

/// 注意:这里需要确保 `target` 保持不变。临时变量和直接写的 `(){...}` 都不行。
class Throttle {
static bool seconds(int timeoutSeconds, Function target, [List<dynamic> positionalArguments, Map<Symbol, dynamic> namedArguments]) =>
duration(Duration(seconds: timeoutSeconds), target, positionalArguments, namedArguments);

static bool duration(Duration timeout, Function target, [List<dynamic> positionalArguments, Map<Symbol, dynamic> namedArguments]) {
if (_throttled.containsKey(target)) {
return false;
}

_print('positionalArguments = $positionalArguments');
_print('namedArguments = $namedArguments');

try {
Function.apply(target, positionalArguments, namedArguments);
} catch (e) {
assert(false, 'Throttle error: $e');
}

final _ActionTarget throttleTarget = _ActionTarget(target, positionalArguments, namedArguments);
_throttled[target] = throttleTarget;
Timer(timeout, () {
_throttled.remove(target);
});

return true;
}

static bool clear(Function target) {
if (_throttled.containsKey(target)) {
_throttled.remove(target);
return true;
}

return false;
}
}

/// 注意:这里需要确保 `target` 保持不变。临时变量和直接写的 `(){...}` 都不行。
class DeBouncer {
static bool seconds(int timeoutSeconds, Function target, [List<dynamic> positionalArguments, Map<Symbol, dynamic> namedArguments]) =>
duration(Duration(seconds: timeoutSeconds), target, positionalArguments, namedArguments);

static bool duration(Duration timeout, Function target, [List<dynamic> positionalArguments, Map<Symbol, dynamic> namedArguments]) {
if (_debounced.containsKey(target)) {
Timer timer = _debounced[target];
timer.cancel();
_debounced.remove(target);
}

_print('positionalArguments = $positionalArguments');
_print('namedArguments = $namedArguments');

Timer actionTimer = Timer(timeout, () {
try {
Function.apply(target, positionalArguments, namedArguments);
} catch (e) {
assert(false, 'DeBouncer error: $e');
}
});
_debounced[target] = actionTimer;

return true;
}

static bool clear(Function target) {
if (_debounced.containsKey(target)) {
Timer timer = _debounced[target];
timer.cancel();
_debounced.remove(target);
return true;
}

return false;
}
}

// _ThrottleTimer allows us to keep track of the target function
// along with it's timer.
class _ActionTarget {
final Function target;
final List<dynamic> positionalArguments;
final Map<Symbol, dynamic> namedArguments;

_ActionTarget(this.target, this.positionalArguments, this.namedArguments);
}
17 changes: 17 additions & 0 deletions lib/map.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/// force to convert Map from Map<dynamic, dynamic> to Map<String, String>
Map<String, String> forceConvertMap(Map<dynamic, dynamic> a) {
if (a is Map) {
try {
Map<String, String> b = Map.from(a);
return b;
} catch (e) {
Map<String, String> c = {};
a.keys.forEach((curKey) {
c.putIfAbsent('$curKey', () => '${a[curKey]}');
});
return c;
}
}

return Map<String, String>();
}
13 changes: 13 additions & 0 deletions lib/type_check.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
bool isValid(dynamic a) {
if (a == null) {
return false;
}

if (a is String) {
return a.isNotEmpty;
} else if (a is List) {
return a.length > 0;
}

return true;
}
76 changes: 73 additions & 3 deletions test/flutter_utils_z_test.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import 'dart:async';

import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_utils_z/flutter_utils_z.dart';
import 'package:flutter_utils_z/flow_control.dart';

void main() {
const MethodChannel channel = MethodChannel('flutter_utils_z');
Expand All @@ -17,7 +19,75 @@ void main() {
channel.setMockMethodCallHandler(null);
});

test('getPlatformVersion', () async {
expect(await FlutterUtils_z.platformVersion, '42');
test('throttle', () async {
var checkStr = 'empty';

void printSeconds(str, {String str2}) {
checkStr = str;
print("Hello World (Throttle.seconds:) $str == $str2");
}

Throttle.seconds(1, printSeconds, ['aaa'], {Symbol('str2'): 'str22'});
expect(checkStr, equals('aaa'));

/// 不会执行
Throttle.seconds(1, printSeconds, ['ddd'], {Symbol('str2'): 'str22'});
expect(checkStr, isNot('ddd'));

Future.delayed(Duration(seconds: 2), () {
Throttle.seconds(5, printSeconds, ['bbb'], {Symbol('str2'): 'str22'});
expect(checkStr, 'bbb');
});

/// 不会执行
Future.delayed(Duration(seconds: 4), () {
Throttle.seconds(1, printSeconds, ['ccc'], {Symbol('str2'): 'str22'});
expect(checkStr, isNot('ccc'));
});

await Future.delayed(Duration(seconds: 10));
});

test('debounce-正常执行', () async {
var checkStr = 'empty';

void printSeconds(str) {
checkStr = str;
print("Hello World (Throttle.seconds:) $str");
}

DeBouncer.seconds(1, printSeconds, ['aaa']);
expect(checkStr, isNot('aaa'));

DeBouncer.seconds(1, printSeconds, ['aaa']);
expect(checkStr, isNot('ccc'));

DeBouncer.seconds(1, printSeconds, ['ddd']);
expect(checkStr, isNot('ddd'));

await Future.delayed(Duration(seconds: 2));
expect(checkStr, ('ddd'));

await Future.delayed(Duration(seconds: 5));
});

test('debounce-取消操作', () async {
var checkStr = 'empty';

void printSeconds(str) {
checkStr = str;
print("Hello World (Throttle.seconds:) $str");
}

DeBouncer.seconds(1, printSeconds, ['aaa']);
expect(checkStr, isNot('aaa'));

DeBouncer.seconds(1, printSeconds, ['ddd']);
expect(checkStr, isNot('ddd'));

DeBouncer.clear(printSeconds);

await Future.delayed(Duration(seconds: 2));
expect(checkStr, 'empty');
});
}

0 comments on commit a6ff3be

Please sign in to comment.