Line data Source code
1 : // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 : // for details. All rights reserved. Use of this source code is governed by a
3 : // BSD-style license that can be found in the LICENSE file.
4 :
5 : import 'dart:async';
6 :
7 : /// A class for running an asynchronous function exactly once and caching its
8 : /// result.
9 : ///
10 : /// An `AsyncMemoizer` is used when some function may be run multiple times in
11 : /// order to get its result, but it only actually needs to be run once for its
12 : /// effect. To memoize the result of an async function, you can create a
13 : /// memoizer outside the function (for example as an instance field if you want
14 : /// to memoize the result of a method), and then wrap the function's body in a
15 : /// call to [runOnce].
16 : ///
17 : /// This is useful for methods like `close()` and getters that need to do
18 : /// asynchronous work. For example:
19 : ///
20 : /// ```dart
21 : /// class SomeResource {
22 : /// final _closeMemo = new AsyncMemoizer();
23 : ///
24 : /// Future close() => _closeMemo.runOnce(() {
25 : /// // ...
26 : /// });
27 : /// }
28 : /// ```
29 : class AsyncMemoizer<T> {
30 : /// The future containing the method's result.
31 : ///
32 : /// This can be accessed at any time, and will fire once [runOnce] is called.
33 10 : Future<T> get future => _completer.future;
34 : final _completer = new Completer<T>();
35 :
36 : /// Whether [runOnce] has been called yet.
37 10 : bool get hasRun => _completer.isCompleted;
38 :
39 : /// Runs the function, [computation], if it hasn't been run before.
40 : ///
41 : /// If [runOnce] has already been called, this returns the original result.
42 : Future<T> runOnce(FutureOr<T> computation()) {
43 20 : if (!hasRun) _completer.complete(new Future.sync(computation));
44 5 : return future;
45 : }
46 : }
|