在forEach循环中填充list之前,我的异步调用正在返回

Jer*_*rry 4 file list async-await dart flutter

我有一个例程,它从设备中获取文件名列表,然后读取文件以构建列表.但是,调用例程始终返回零项.我打印文件名,所以我知道它们存在,但是,在我读取文件之前,似乎异步正在返回.我在进行HTTP调用时使用了类似的代码.但是,这里的某些事情导致例程返回列表,即使它尚未完成.也许,我有可能在错误的时间召唤它?我在这里调用retrieveItems:

@override
  void initState() {
    super.initState();
    retrieveItems();
  }
Run Code Online (Sandbox Code Playgroud)

最终我会有一个刷新按钮,但是现在我只想在列表中填充文件中的数据......

--------------------

被呼叫者

Future<List<String>> readHeaderData() async {
  List<String> l = new List();
  List<String> files = await readHeaders(); // Gets filenames
  files.forEach((filename) async {
    final file = await File(filename);
    String contents = await file.readAsString();
    User usr = User.fromJson(json.decode(contents));
    String name = usr.NameLast + ", " + usr.NameFirst;
    print(name);
    l.add(name);
  }
  return l;
Run Code Online (Sandbox Code Playgroud)

呼叫者

void retrieveItems() async {
  LocalStorage storage = new LocalStorage();
  await storage.readHeaderData().then((item) {
      try {
        if ((item != null ) &&(item.length >= 1)) {
          setState(() {
            users.clear();
            _users.addAll(item);
          });
        } else {
          setState(() {
            _users.clear();
            final snackbar = new SnackBar(
              content: new Text('No users found.'),
            );
            scaffoldKey.currentState.showSnackBar(snackbar);
          });
        }
      } on FileNotFoundException catch (e) {
        print(e.toString()); //For debug only
        setState(() {
          _users.clear();
        });
      });
    }
  });
Run Code Online (Sandbox Code Playgroud)

小智 26

也可以

await Future.forEach(yourList, (T elem) async { ...async staff });
Run Code Online (Sandbox Code Playgroud)


Dun*_*nes 16

为了扩展 Günter 关于 using 的评论list.map(f),这里有一个转换forEach调用以使其正常工作的示例。

破碎的例子

错误地假设forEach将等待期货:

Future<void> brokenExample(List<String> someInput) async {    
  List<String> results;

  someInput.forEach((input) async {
    String result = await doSomethingAsync(input);
    results.add(result);
  });

  return results;
}
Run Code Online (Sandbox Code Playgroud)

更正的例子

等待异步函数完成,使用Future.wait.map()

Future<void> correctedExample(List<String> someInput) async {
  List<String> results;

  await Future.wait(someInput.map((input) async {
    String result = await doSomethingAsync(input);
    results.add(result);
  }));

  return results;
}
Run Code Online (Sandbox Code Playgroud)


Gün*_*uer 15

这段代码

Future<List<String>> readHeaderData() async {
  List<String> l = new List();
  List<String> files = await readHeaders(); // Gets filenames
  files.forEach((filename) async {
    final file = await File(filename);
    String contents = await file.readAsString();
    User user = User.fromJson(json.decode(contents));
    String name = user.NameLast + ", " + user.NameFirst;
    print(name);
    l.add(name);
  }
  return l;
}
Run Code Online (Sandbox Code Playgroud)

返回列表l,然后处理asyc forEach(...)回调

如果你改成它

Future<List<String>> readHeaderData() async {
  List<String> l = new List();
  List<String> files = await readHeaders(); // Gets filenames
  for(var filename in files) {  /// <<<<==== changed line
    final file = await File(filename);
    String contents = await file.readAsString();
    User user = User.fromJson(json.decode(contents));
    String name = user.NameLast + ", " + user.NameFirst;
    print(name);
    l.add(name);
  }
  return l;
}
Run Code Online (Sandbox Code Playgroud)

在处理所有文件名之前,函数不会返回.

files.forEach((filename) async {
Run Code Online (Sandbox Code Playgroud)

意味着你可以await在回调中使用,但forEach不关心(filename) async {...}返回什么.

  • 有一个列表 `files` 和一个方法 `forEach(f)`,它在内部调用你传递给它的函数 `f`,为 `files` 中的每个元素。`forEach()` 不返回任何内容。如果您改为使用`list.map(f)`,那么对于`files` 中的每个项目,您将从`f` 返回一个`Future`。然后你可以使用 `await Future.all(files.map(f))` 它将等待所有 Futures,然后才继续下面的代码。循环`for(...) { ... }` 不仅仅是一个调用传递给它的函数的方法,它还是一种语言结构,语句和表达式按顺序执行。 (2认同)