|
|
@@ -0,0 +1,131 @@
|
|
|
+import 'dart:async';
|
|
|
+
|
|
|
+import 'package:flutter/widgets.dart';
|
|
|
+
|
|
|
+import 'async_typeof.dart';
|
|
|
+import 'cancel_future.dart';
|
|
|
+
|
|
|
+class AsyncUtil {
|
|
|
+ AsyncUtil._();
|
|
|
+
|
|
|
+ static CancelableFuture<T> retryWithExponentialBackoff<T>(
|
|
|
+ FutureCallback<T> callback,
|
|
|
+ int maxRetry,
|
|
|
+ Duration initialInterval,
|
|
|
+ Predicate<dynamic> predicate) {
|
|
|
+ Completer<T> completer = Completer<T>();
|
|
|
+ int retryCount = 0;
|
|
|
+ Timer? timer;
|
|
|
+
|
|
|
+ void attempt() {
|
|
|
+ callback().then((value) {
|
|
|
+ if (!completer.isCompleted) {
|
|
|
+ completer.complete(value);
|
|
|
+ }
|
|
|
+ }).catchError((error) {
|
|
|
+ if (retryCount < maxRetry && predicate(error)) {
|
|
|
+ retryCount++;
|
|
|
+ Duration nextInterval = initialInterval * (1 << (retryCount - 1));
|
|
|
+ timer = Timer(nextInterval, attempt);
|
|
|
+ } else {
|
|
|
+ if (!completer.isCompleted) {
|
|
|
+ completer.completeError(error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ attempt();
|
|
|
+
|
|
|
+ return CancelableFuture<T>(() {
|
|
|
+ timer?.cancel();
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ static CancelableFuture<T> retryWhen<T>(FutureCallback<T> callback,
|
|
|
+ int maxRetry, Duration interval, Predicate<dynamic> predicate) {
|
|
|
+ Completer<T> completer = Completer<T>();
|
|
|
+ int retryCount = 0;
|
|
|
+ Timer? timer;
|
|
|
+
|
|
|
+ void attempt() {
|
|
|
+ callback().then((value) {
|
|
|
+ if (!completer.isCompleted) {
|
|
|
+ completer.complete(value);
|
|
|
+ }
|
|
|
+ }).catchError((error) {
|
|
|
+ if (retryCount < maxRetry && predicate(error)) {
|
|
|
+ retryCount++;
|
|
|
+ timer = Timer(interval, attempt);
|
|
|
+ } else {
|
|
|
+ if (!completer.isCompleted) {
|
|
|
+ completer.completeError(error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ attempt();
|
|
|
+
|
|
|
+ return CancelableFuture<T>(() {
|
|
|
+ timer?.cancel();
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ static CancelableFuture<T> retry<T>(
|
|
|
+ FutureCallback<T> callback, int maxRetry, Duration interval) {
|
|
|
+ return retryWhen(callback, maxRetry, interval, (error) => true);
|
|
|
+ }
|
|
|
+
|
|
|
+ static CancelableFuture<T> delay<T>(
|
|
|
+ FutureCallback<T> callback, Duration interval) {
|
|
|
+ Timer? timer;
|
|
|
+ return CancelableFuture<T>(
|
|
|
+ () {
|
|
|
+ timer?.cancel();
|
|
|
+ },
|
|
|
+ futureCompleter: (completer) {
|
|
|
+ timer = Timer(interval, () {
|
|
|
+ callback()
|
|
|
+ .then(completer.complete)
|
|
|
+ .catchError(completer.completeError);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ ///实际delay第一次执行的时间为delay+interval
|
|
|
+ static CancelableFuture<T> interval<T>(FutureCallback<T> callback,
|
|
|
+ Duration delay, Duration interval, int times) {
|
|
|
+ Timer? timer;
|
|
|
+ Timer? delayTimer;
|
|
|
+ int counter = 0;
|
|
|
+ Completer<T> completer = Completer<T>();
|
|
|
+
|
|
|
+ void tick() {
|
|
|
+ if (counter < times) {
|
|
|
+ callback().then((value) {
|
|
|
+ if (!completer.isCompleted) {
|
|
|
+ completer.complete(value);
|
|
|
+ }
|
|
|
+ }).catchError((error) {
|
|
|
+ if (!completer.isCompleted) {
|
|
|
+ completer.completeError(error);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ counter++;
|
|
|
+ } else {
|
|
|
+ timer?.cancel();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ delayTimer = Timer(delay, () {
|
|
|
+ timer = Timer.periodic(interval, (Timer t) => tick());
|
|
|
+ });
|
|
|
+
|
|
|
+ return CancelableFuture<T>(() {
|
|
|
+ delayTimer?.cancel();
|
|
|
+ timer?.cancel();
|
|
|
+ });
|
|
|
+ }
|
|
|
+}
|