8

さまざまなデータ関連のタスクを実行するサーバー側の Dart クラスを作成しようとしています。これらのタスクはすべて、最初に初期化されたデータベースに依存しています。問題は、データベースの初期化が非同期で行われることです (Future を返します)。私は最初に初期化コードをコンストラクターに入れようとしましたが、実行可能ではないように思われるため、このアプローチをあきらめました。

データにアクセスするメソッド呼び出しの最初のステップとして、DB の初期化を強制する方法を見つけようとしています。つまり、以下の attemptsLogin() が呼び出されたときに、まず DB が初期化されているかどうかを確認し、必要に応じて初期化したいと考えています。

ただし、障害が 2 つあります。データベースが初期化されていない場合、コードは簡単です。データベースを初期化し、返された Future の then() メソッドを使用して残りの関数を実行します。データベースがまだ初期化されていない場合、then() メソッドを何にアタッチすればよいですか?

関連する 2 番目の質問は、データベースが現在初期化されているが、このプロセスがまだ完了していない場合はどうなるかということです。この「進行中」の Future を取得して返すにはどうすればよいですか?

これは、私が取り組もうとしているコードの基本的な要点です。

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
    });
  }
}

よろしくお願いいたします。

グレッグ

4

5 に答える 5

12

戻るだけ

return new Future<bool>.value(true); 
// or any other value instead of `true` you want to return.
// or none
// return new Future.value();
于 2014-07-10T14:06:40.223 に答える
2

考えられる解決策の 1 つ:

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

より良い解決策があると思いますが、これはあなたの質問に答えようとする試みにすぎません(私があなたを正しく理解している場合)。

PSは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");
  }
}
于 2014-07-10T15:18:15.483 に答える
0

Dart では Future<Type> は null 不可です。つまり、値に初期化する必要があります。そうしないと、Dart は次のエラーをスローします。

エラー: フィールドの型 'Future<Type>' で null が許可されていないため、フィールドを初期化する必要があります。

Future<Type> を初期化するには、次の例を参照してください。

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

ここで、「Future String」は String であるため、上記のコードは Future<String> のインスタンスを返します。

空白/空の Future を作成する方法の問題に来て、空の Future List を初期化するために次のコードを使用しました。

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

このリンクは、Flutter と Dart の先物を理解するのに非常に役立つことがわかりました: https://meysam-mahfouzi.medium.com/understanding-future-in-dart-3c3eea5a22fb

于 2022-01-19T22:00:22.470 に答える