【问题标题】:How do I create a blank Future in Dart + how do I return a future currently in progress?如何在 Dart 中创建一个空白 Future + 如何返回当前正在进行的 Future?
【发布时间】:2014-07-10 14:02:18
【问题描述】:

我正在尝试创建一个执行各种与数据相关的任务的服务器端 Dart 类。所有这些任务都依赖于首先初始化的数据库。问题是数据库的初始化是异步发生的(返回一个未来)。我首先尝试将初始化代码放入构造函数中,但由于它似乎不可行而放弃了这种方法。

我现在正试图弄清楚如何将数据库初始化作为任何访问数据的方法调用的第一步。所以换句话说,当在下面调用尝试登录()时,我想首先检查数据库是否已初始化,并在必要时对其进行初始化。

但是,有两个障碍。如果数据库还没有初始化,代码很简单——初始化数据库,然后使用返回的 future 的 then() 方法来完成剩下的功能。如果数据库尚未初始化,我将 then() 方法附加到什么?

第二个相关问题是当数据库当前正在初始化但此过程尚未完成时会发生什么?我如何才能拉入并返回这个“进行中”的未来?

这是我试图解决的代码的基本要点:

class DataManager {
  bool DbIsReady = false;
  bool InitializingDb = false;
  Db _db;

  Future InitMongoDB() {
    print("Initializing MongoDB");
    InitializingDb = true;
    _db = new Db("mongodb://127.0.0.1/test");
    return _db.open().then((_) {
      DbIsReady = true;
      InitializingDb = false;
    });
  }  

  Future<List> attemptLogin(String username, String password) {
    Future firstStep;
    if ((!DbIsReady) && (!InitializingDb) {
       Future firstStep = InitMongoDB()
    }
    else if (InitializingDb) {
       // Need to return the InitMongoDB() Future that's currently running, but how?
    }
    else {
       // How do I create a blank firstStep here? 
    }

    return firstStep.then((_) {
      users = _db.collection("users");
      return // ... rest of code cut out for clarity
    });
  }
}

提前感谢您的帮助,

格雷格

【问题讨论】:

  • 我会发现在任何与数据库相关的代码可以运行之前而不是在每个数据库操作之前确保数据库初始化更容易。你这样做有理由吗?
  • @Günter 我最初尝试在类构造函数中进行数据库初始化,但在测试时遇到了问题。我在 StackOverflow 上发布了一个关于它的问题:stackoverflow.com/questions/24592070/…,但没有得到关于如何解决问题的好的答案。
  • 我为您的其他问题添加了答案。我还没有测试过它,但至少它应该可以帮助你理解这个想法。

标签: dart dart-async


【解决方案1】:

直接返回

return new Future<bool>.value(true); 
// or any other value instead of `true` you want to return.
// or none
// return new Future.value();

【讨论】:

    【解决方案2】:

    让未来保持活力:

    class DataManager {
      Future _initializedDb;
    
      Future initMongoDb() { ... }
    
      Future<List> attemptLogin(String username, String password) {
        if (_initializedDb == null) {
           _initializedDb = initMongoDB();
        }
        return _initializedDb.then((db) {
          users = db.collection("users");
          return // ... rest of code cut out for clarity
        });
      }
    }
    

    您可能需要注意错误情况。如果您想处理 initMongoDB 或之后的错误,这取决于您。

    【讨论】:

    • 你是说你可以链接到一个完整的未来,还是一个未来的中期执行?我没有在任何示例中看到这一点,也没有这方面的文档。
    • 作为未来的用户,您永远不知道该值是否已经存在。所以这是正常行为。但是,当出现错误时,future 必须至少有一个侦听器。否则,该错误将被视为未处理,并可能导致您的程序崩溃。这意味着您应该尽快添加至少一个错误处理程序。
    【解决方案3】:

    可能的解决方案之一:

    import "dart:async";
    
    void main() {
      var dm = new DataManager();
      var selectOne = dm.execute("SELECT 1");
      var selectUsers = dm.execute("SELECT * FROM users");
      var users = selectOne.then((result) {
        print(result);
        return selectUsers.then((result) {
          print(result);
        });
      });
    
      users.then((result) {
        print("Goodbye");
      });
    }
    
    class Event {
      List<Function> _actions = new List<Function>();
      bool _raised = false;
    
      void add(Function action) {
        if (_raised) {
          action();
        } else {
          _actions.add(action);
        }
      }
    
      void raise() {
        _raised = true;
        _notify();
      }
    
      void _notify() {
        if (_actions.isEmpty) {
          return;
        }
    
        var actions = _actions.toList();
        _actions.clear();
        for (var action in actions) {
          action();
        }
      }
    }
    
    class DataManager {
      static const int _STATE_NOT_INITIALIZED = 1;
      static const int _STATE_INITIALIZING = 2;
      static const int _STATE_READY = 3;
    
      Event _initEvent = new Event();
      int _state = _STATE_NOT_INITIALIZED;
    
      Future _init() {
        if (_state == _STATE_NOT_INITIALIZED) {
          _state = _STATE_INITIALIZING;
          print("Initializing...");
          return new Future(() {
            print("Initialized");
            _state = _STATE_READY;
            _initEvent.raise();
          });
        } else if (_state == _STATE_INITIALIZING) {
          print("Waiting until initialized");
          var completer = new Completer();
          _initEvent.add(() => completer.complete());
          return completer.future;
        }
    
        return new Future.value();
      }
    
      Future execute(String query, [Map arguments]) {
        return _init().then((result) {
          return _execute(query, arguments);
        });
      }
    
      Future _execute(String query, Map arguments) {
        return new Future.value("query: $query");
      }
    }
    

    输出:

    Initializing...
    Waiting until initialized
    Initialized
    query: SELECT 1
    query: SELECT * FROM users
    Goodbye
    

    我认为存在更好的解决方案,但这只是试图回答您的问题(如果我正确理解您的话)。

    附注2014 年 7 月 11 日编辑

    稍作修改(带有错误处理)的示例。

    import "dart:async";
    
    void main() {
      var dm = new DataManager();
      var selectOne = dm.execute("SELECT 1");
      var selectUsers = dm.execute("SELECT * FROM users");
      var users = selectOne.then((result) {
        print(result);
        return selectUsers.then((result) {
          print(result);
        });
      });
    
      users.then((result) {
        print("Goodbye");
      });
    }
    
    class DataManager {
      static const int _STATE_NOT_INITIALIZED = 1;
      static const int _STATE_INITIALIZING = 2;
      static const int _STATE_READY = 3;
      static const int _STATE_FAILURE = 4;
    
      Completer _initEvent = new Completer();
      int _state = _STATE_NOT_INITIALIZED;
    
      Future _ensureInitialized() {
        switch (_state) {
          case _STATE_NOT_INITIALIZED:
            _state = _STATE_INITIALIZING;
            print("Initializing...");
            new Future(() {
              print("Initialized");
              _state = _STATE_READY;
              // throw null;
              _initEvent.complete();
            }).catchError((e, s) {
              print("Failure");
              _initEvent.completeError(e, s);
            });
    
            break;    
          case _STATE_INITIALIZING:
            print("Waiting until initialized");
            break;
          case _STATE_FAILURE:
            print("Failure detected");
            break;
          default:
            print("Aleady intialized");
            break;
        }
    
        return _initEvent.future;
      }
    
      Future execute(String query, [Map arguments]) {
        return _ensureInitialized().then((result) {
          return _execute(query, arguments);
        });
      }
    
      Future _execute(String query, Map arguments) {
        return new Future.value("query: $query");
      }
    }
    

    【讨论】:

    • 您认为这个问题的更好解决方案是什么?
    【解决方案4】:

    对于那些仍然想知道如何在 Dart 中创建空白 Future 并稍后完成它们的人,您应该像下一个示例一样使用 Completer 类。

    class AsyncOperation {
      final Completer _completer = new Completer();
    
      Future<T> doOperation() {
        _startOperation();
        return _completer.future; // Send future object back to client.   
      }
    
      // Something calls this when the value is ready.   
      void finishOperation(T result) {
        _completer.complete(result);   
      }
    
      // If something goes wrong, call this.   
      void _errorHappened(error) {
          _completer.completeError(error);   
      }
    }
    

    【讨论】:

      【解决方案5】:

      Future 在 Dart 中不可为空,这意味着您必须将其初始化为一个值。如果不这样做,Dart 会抛出以下错误:

      错误:字段应该被初始化,因为它的类型 'Future' 不允许为空。

      要初始化 Future,请参见以下示例:

      Future<String> myFutureString = Future(() => "Future String");
      

      这里的“Future String”是一个字符串,所以上面的代码返回了一个 Future 的实例。

      所以谈到如何创建一个空白/空的 Future 的问题,我使用以下代码来初始化一个空的 Future 列表。

      Future<List> myFutureList = Future(() => []);
      

      我发现这个链接对于理解 Flutter 和 Dart 中的 Futures 非常有用:https://meysam-mahfouzi.medium.com/understanding-future-in-dart-3c3eea5a22fb

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-20
        • 1970-01-01
        • 1970-01-01
        • 2020-01-05
        相关资源
        最近更新 更多