【问题标题】:Flutter - Dart : wait a forEach endsFlutter - Dart:等待 forEach 结束
【发布时间】:2019-05-22 00:28:30
【问题描述】:

我尝试使用从 Firebase 数据库检索到的每个节点中的数据修改字符串,然后使用修改后的字符串(称为“内容”)写入文件。

这是我尝试过的:

// Retrieve initial content from Firebase storage
var data = await FirebaseStorage.instance.ref().child("...").getData(1048576);
var content = new String.fromCharCodes(data);

// Edit content with each node from Firebase database
final response = await FirebaseDatabase.instance.reference().child('...').once();
response.value.forEach((jsonString) async {
     ...
     // cacheManager.getFile returns a Future<File>
     cacheManager.getFile(signedurl).then((file){ 
         // Modify content
         content=content.replaceAll('test',file.path);
     });
});

// Finally write the file with content
print("test");
final localfile = File('index.html');
await localfile.writeAsString(content);

结果:

“test”在 forEach 结束之前显示。

我发现我们可以在 Dart (https://groups.google.com/a/dartlang.org/forum/#!topic/misc/GHm2cKUxUDU) 中做:

等待 Future.forEach

但在我的情况下,如果我这样做:等待 Future.response.value.forEach(听起来有点奇怪)

然后我得到:

找不到吸气剂:“响应”。 等待 Future.response.value.forEach((jsonString) async {

在用新内容写入文件之前如何等待 forEach 结束(修改了“内容”)?

有什么想法吗?

【问题讨论】:

  • 我不知道 Dart,但我认为您应该使用一些 map 值而不是 forEach 值,以便返回 Promises 数组(或 Dart 语言中的类似值) ,Futures 也许?)能够为所有人“等待”。在这里,您只是创建了一些异步行为,但它们并没有阻塞,因此要执行 print("test") 代码。

标签: firebase firebase-realtime-database dart flutter


【解决方案1】:

如果您使用for(... in ) 而不是forEach,您可以使用async/await

Future someMethod() async {
  ...

  for(final jsonString in response.value) {
     ...
     // cacheManager.getFile returns a Future<File>
     cacheManager.getFile(signedurl).then((file){ 
         // Modify content
         content=content.replaceAll('test',file.path);
     });
  });
}

使用forEach,每个jsonString 的调用都会立即触发,并且在其中await 有效,但forEach 的返回类型为void,不能等待,只有Future 可以。

【讨论】:

    【解决方案2】:

    您将 forEach 的回调定义为 async,这意味着它异步运行。换句话说:回调内部的代码独立于回调外部的代码运行。这正是print("test"); 在回调内部的代码之前运行的原因。

    最简单的解决方案是将所有需要信息的代码从回调移到回调中。但也可能有一种方法来await all of the asynchronous callbacks,类似于你已经在上面调用await once

    更新我开始做我认为你想做的事情。使用这个 JSON:

    {
      "data" : {
        "key1" : {
          "created" : "20181221T072221",
          "name" : "I am key1"
        },
        "key2" : {
          "created" : "20181221T072258",
          "name" : "I am key 2"
        },
        "key3" : {
          "created" : "20181221T072310",
          "name" : "I am key 3"
        }
      },
      "index" : {
        "key1" : true,
        "key3" : true
      }
    }
    

    我可以读取索引,然后将数据加入:

    final ref = FirebaseDatabase.instance.reference().child("/53886373");
    final index = await ref.child("index").once();
    List<Future<DataSnapshot>> futures = [];
    index.value.entries.forEach((json) async {
      print(json);
      futures.add(ref.child("data").child(json.key).once());
    });
    Future.wait(futures).then((List<DataSnapshot> responses) {
      responses.forEach((snapshot) {
        print(snapshot.value["name"]);
      });
    });
    

    【讨论】:

    • 如何实现firestore
    • Firestore 的代码应该非常相似,因为它也返回 Futures。如果您很难让它发挥作用,请使用重现 尝试过的内容的最少代码打开一个新问题。
    【解决方案3】:

    你试过了吗:

    File file = await cacheManager.getFile(signedurl);
    content = content.replaceAll('test', file.path);
    

    代替:

    cacheManager.getFile(signedurl).then((file){ ...});
    

    编辑:

    这里有一个更完整的例子,试图复制你所拥有的。我使用for 循环而不是forEach() 方法:

    void main () async {
      List<String> str = await getFuture();
      print(str);
      var foo;
    
      for (var s in str) {
        var b = await Future(() => s);
        foo = b;
      }
    
      print('finish $foo');
    }
    
    getFuture() => Future(() => ['1', '2']); 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-09-12
      • 2018-11-16
      • 1970-01-01
      • 2019-06-28
      • 2020-02-22
      • 2019-01-31
      • 2013-12-03
      相关资源
      最近更新 更多