diff --git a/CHANGELOG.md b/CHANGELOG.md index c89049a..febc23e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ ## 2.12.0-wip - -- Require Dart 3.4 +* Can decide `runOnce` method of `AsyncMemoizer` will store exception or not. +* Require Dart 3.4 ## 2.11.0 diff --git a/lib/src/async_memoizer.dart b/lib/src/async_memoizer.dart index c05c927..12588c0 100644 --- a/lib/src/async_memoizer.dart +++ b/lib/src/async_memoizer.dart @@ -5,7 +5,9 @@ import 'dart:async'; /// A class for running an asynchronous function exactly once and caching its -/// result. +/// result. If you doesn't want to cache Exception then you can set +/// [_canCacheException] to false. +/// /// /// An `AsyncMemoizer` is used when some function may be run multiple times in /// order to get its result, but it only actually needs to be run once for its @@ -27,6 +29,9 @@ import 'dart:async'; /// } /// ``` class AsyncMemoizer { + AsyncMemoizer({bool canCacheException = true}): + _canCacheException = canCacheException; + /// The future containing the method's result. /// /// This can be accessed at any time, and will fire once [runOnce] is called. @@ -36,11 +41,28 @@ class AsyncMemoizer { /// Whether [runOnce] has been called yet. bool get hasRun => _completer.isCompleted; + ///Default is set to true. + ///If we set this variable to false. + ///On the initial run, if callback returned the [Exception]. + ///Next time, we can reRun the callback for the successful attempt. + final bool _canCacheException; + /// Runs the function, [computation], if it hasn't been run before. /// /// If [runOnce] has already been called, this returns the original result. - Future runOnce(FutureOr Function() computation) { - if (!hasRun) _completer.complete(Future.sync(computation)); + Future runOnce(FutureOr Function() computation) async { + if (!hasRun) { + if (_canCacheException) { + _completer.complete(Future.sync(computation)); + } else { + try { + var value = await computation(); + _completer.complete(value); + } catch (error) { + rethrow; + } + } + } return future; } } diff --git a/test/async_memoizer_test.dart b/test/async_memoizer_test.dart index 490b389..e82c123 100644 --- a/test/async_memoizer_test.dart +++ b/test/async_memoizer_test.dart @@ -9,6 +9,14 @@ void main() { late AsyncMemoizer cache; setUp(() => cache = AsyncMemoizer()); + test('should not store exception when callback throws exception', () async { + Future asyncFunctionThatThrows() { + throw Exception(); + } + var cacheFuture = cache.runOnce(asyncFunctionThatThrows); + await expectLater(cacheFuture,throwsA(isException)); + }); + test('runs the function only the first time runOnce() is called', () async { var count = 0; expect(await cache.runOnce(() => count++), equals(0));