Dart 内部的 wait 到底做了什么?

2024-04-08

我正在开发一个需要使用本地存储的颤振应用程序。由于Android中的文档目录路径将在Future中给出,因此每次我想使用该路径时,我都必须检查future是否完成。

代码可能类似于下面

class DataStructure {
  late Future<Directory> _dir = getApplicationDocumentsDirectory();

  Future<void> read(String fileName) async {
    Directory dir = await _dir;

    // Do something using dir
  }
}

这可能很愚蠢,但我大部分时间都在编写 C++ 代码,所以我想减少将函数推送到事件队列的次数以获得更好的性能(我猜编译器会用以下命令来削减异步函数)await进入“函数”以推送到事件队列)。因此,我编写了实验代码来检查等待已完成的未来是否会切断控制流。 (我的意思是,在最新版本的 Dart 中,异步函数将执行直到第一个“await”关键字出现。我想知道如果 future 已经完成,情况是否仍然如此。)

Future<void> voidFuture(String name) async {
  print('$name: voidFuture');
}

Future<void> printSingle(String name, int index) async {
  print('$name: -- index = $index');
}

// This emit function will print one line each time
// it gets chance to be executed.

// Because the 'await' keyword will cut the control flow,
// it can only print once each time it's executed,
// and must wait for the next chance to print again.

// This feature makes it appropriate for testing
// when and where the control flow is cut,
// as each cut will lead to one line of output.
Future<void> emit(String name, int count) async {
  for (int index = 0; index != count; ++index) {
    await printSingle(name, index);
  }
}

Future<void> task_0() async {
  const String name = 'task_0';
  Future<void> emitFinish = emit(name, 3);
  await voidFuture(name);
  print('$name: output after await');
  await emitFinish;
}

在我的环境中运行task_0(Dart SDK版本:2.18.5(稳定)在“windows_x64”上)给出如下输出:

task_0: -- index = 0
task_0: voidFuture
task_0: -- index = 1
task_0: output after await
task_0: -- index = 2

这和我的预期是一样的。当我改变时奇怪的事情发生了emit()功能:

Future<void> emit(String name, int count) async {
  for (int index = 0; index != count; ++index) {
    // Before:
    // await printSingle(name, index);
    // After:
    await Future(() {
      print('$name: -- index = $index');
    });
  }
}

那么输出就变成了

task_0: voidFuture
task_0: output after await
task_0: -- index = 0
task_0: -- index = 1
task_0: -- index = 2

第三行对我来说毫无意义,-- index = 0紧接着output after await。似乎函数比构造函数的 future 更有特权?

我的主要问题是“‘await’会等待一个完成的未来吗?”,所以我写了下面的代码:

Future<String> stringFuture() async {
  return '.';
}

Future<void> task_3() async {
  const String name = 'task_3';
  Future<void> emitFinish = emit(name, 4);
  Future<String> futureString = stringFuture();
  print('$name: before await of futureString');
  await futureString;
  print('$name: 1st await of futureString over');
  await 1;
  print('$name: 1st await of constant over');
  await 2;
  print('$name: 2nd await of constant over');
  await emitFinish;
}

与第一个版本emit(),输出是

task_3: -- index = 0
task_3: before await of futureString
task_3: -- index = 1
task_3: 1st await of futureString over
task_3: -- index = 2
task_3: 1st await of constant over
task_3: -- index = 3
task_3: 2nd await of constant over

这意味着即使await对于常量积分,会将其后面的行推入事件队列。

(当然,有了第二个版本emit()它的所有输出都在最后一个之后print() in task_3(),我不知道为什么)

我知道有很多解决方法,其中之一将使用T? value在第一次之后分配Future<T>完成,并检查是否value == null每次使用它。

但我想问的问题是:

  • 关键字是什么await内部做?请提供足以解释上述现象的详细信息。

  • 有什么办法可以覆盖默认值await行为?例如,通过重写方法?

  • 首选的使用方式是什么Future值很多倍?

  • (与上面无关)如何在 Flutter 的欢迎页面停下来等待这些异步函数,例如,

    getApplicationDocumentsDirectory()
    

    在构建所有小部件之前完成?

我从谷歌得到的大多数结果都是关于async and await适合初学者的关键字,我找不到太多解释其行为的材料await in Dart API 参考文档 https://api.dart.dev/stable/2.18.5/dart-async/Future-class.html.

谢谢你拯救了一颗破碎的心await>_


await is 句法糖 https://en.wikipedia.org/wiki/Syntactic_sugar用于通过注册回调FutureAPI。例如:

Future<int> foo() async {
  bar();

  var x = await someIntFuture();
  return otherStuff(x);
}

基本上转化为:

Future<int> foo() {
  bar();

  return someIntFuture.then((x) {
    return otherStuff(x);
  });
}

await注册一个Future.then回调并返回新的Future。它返回一个Future意思是await总是产生(即使在诸如await null)。这也是为什么当您调用async函数,其主体同步执行,直到到达第一个await.

第三行对我来说毫无意义,-- index = 0紧接着output after await。似乎函数比构造函数的 future 更有特权?

From 的文档Future构造函数 https://api.dart.dev/stable/dart-async/Future/Future.html:

创建一个包含调用结果的 futurecomputation异步地与Timer.run.

您提供给的回调Future构造函数是异步调用的;这是预定的。这与调用不同async函数,如前所述,首先尽可能同步执行。

我的主要问题是“‘等待’会等待一个已经完成的未来吗?”

没关系,如果Future是否已经完成。await总是有产出。

有什么办法可以覆盖默认值await行为?例如,通过重写方法?

如上所述,await是语法糖。你可以做的是创建一个类来实现FutureAPI 和句柄.then不同的是(这就是 Flutter 的SynchronousFuture https://api.flutter.dev/flutter/foundation/SynchronousFuture-class.html类确实如此),但我不会推荐它(出于同样的原因SynchronousFuture文档不鼓励其使用)。

首选的使用方式是什么Future值很多倍?

视情况而定。一般来说,尝试await the Future一次并将结果存储在某处(例如局部变量中)。否则我只会await the Future多次,不必担心,直到有证据表明它对性能至关重要。

(与上面无关)如何在Flutter中停止在欢迎页面等待这些异步函数

依靠。对于某些事情,您可以简单地让您的main功能async and await在调用之前您想要执行的任何异步初始化runApp。在其他情况下(特别是对于长时间运行的情况),您应该使用FutureBuilder https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html.

(另外,以后应该单独提出单独的问题。)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Dart 内部的 wait 到底做了什么? 的相关文章

随机推荐

  • Rails 2:当 id 1 不存在时,Model.find(1) 给出 ActiveRecord 错误

    我正在使用 Rails 2 3 5 如果我给出Model find 1 如果 1 不在数据库中 则返回 ActiveRecord 错误 是否应该回归nil正如以下情况Model find by column 这是预期的行为 我认为 Davi
  • 使用 JSON 字符串解析 URL 时捕获 IllegalArgumentException

    我需要使用 JSON 数据制定一个 url 如下所示 http someurl com passfail parameter http someurl com passfail parameter data1 123456789 data2
  • 将EhCache磁盘存储内容加载到内存中

    正如中所述EhCache文档 http ehcache org documentation get started storage options 在实践中 这意味着持久内存缓存将启动 其所有元素都在磁盘上 因此 Ehcache 设计不会在
  • 如何获得最大可能的精度? (Python - 十进制)

    我正在使用Decimal https docs python org 2 library decimal html用于需要精度的操作的类 我想使用 最大可能 的精度 我的意思是 程序运行的系统可以处理的精确度 要设置一定的精度很简单 imp
  • 在 Linq to Sql 中调用 InsertOnSubmit 时出现 NullReferenceException

    我尝试使用 LINQ to SQL 将新对象插入到数据库中 但当我在下面的代码片段中调用 InsertOnSubmit 时 出现 NullReferenceException 我传入一个名为 FileUploadAudit 的派生类 并设置
  • 移动 .git 目录

    我有一个在项目学习曲线早期创建的存储库 随着我了解更多 我意识到这会产生问题 因为我想要跟踪的一些文件在编译的源代码中并不需要 我想做的是创建一个新的 项目 父目录 将现有的源目录移动到该父目录中 并将不需要编译的文件迁移到该父目录中 用
  • 码头服务器配置

    我使用 Jetty 9 但配置有一些问题 我简单的 REST 效果很好 但是当我尝试向所有请求和错误处理程序添加新标头时 问题就开始了 我能够处理标头的唯一方法是将以下代码添加到每个响应中 return Response ok murals
  • 使用Python正确解析PDF段落

    我正在创建一个 Python 脚本 该脚本应该从系统加载一堆 PDF 文件 进行一些数据分析并输出结果 数据分析的本质是 我必须按段落解析 PDF 并且对于每个段落 我必须迭代每个短语 检查是否满足某些条件 我目前正在使用 Tika 进行解
  • 调用对象的多个方法?

    我尝试在单个对象上调用多个函数 但我认为我的语法失败了 你能纠正我吗 objMetaDaten gt setStrTitle test gt setStrBeschreibung test gt setStrUeberschrift tes
  • 如何删除 csv 文件中的整行并将更改保存在同一文件上?

    我是 python 新手 尝试修改 csv 文件 以便我能够根据给定列表删除具有特定字段的特定行 在我当前的代码中 我得到了我想要删除的行 但我无法删除它并将更改保存在同一文件上 替换 import os sys glob import t
  • Laravel 5.3 约束渴望加载不起作用

    我有两个型号User and Profile处于一对一的关系中 我想检索所有用户所在位置profile status TRUE使用以下代码 users User with profile gt function query query gt
  • MATLAB 版本 7 中的 pdist2 等效项

    我需要在matlab中计算两个矩阵之间的欧几里德距离 目前我正在使用 bsxfun 并计算距离 如下所示 我附上代码片段 for i 1 4754 test data fea test i d sqrt sum bsxfun minus t
  • Git RPC 失败;结果=22,HTTP 代码=400

    我在 StackOverflow 上阅读过 发现了与我类似的情况 但没有一个足够接近让我弄清楚下一步应该做什么 我正在尝试提取构建我正在开发的项目 git clone 所需的库的新副本 我发出以下命令 启用 GIT CURL VERBOSE
  • 必要时无法加载 Opencv 库

    我尝试在使用 OpenCV 的必要项目中使用相机 我在 pro 文件中有这个 INCLUDEPATH C OpenCV 2 3 1 android bin OpenCV 2 3 1 include C OpenCV 2 3 1 androi
  • 如何在 jQuery 中触发两个元素的 mouseout 事件?

    假设我有两个独立的 div A 和 B 它们在一个角处重叠 A B 我想在鼠标离开时触发一个事件bothA和B 我试过这个 a b mouseleave function 但如果鼠标离开任一节点 则会触发该事件 我希望一旦鼠标不在任何一个节
  • Zurb Foundation 5:网格列堆叠

    我是基础新手 我只知道如何使用网格的基本概念 I have these 3 columns that need to be stacked see mobile image when viewed on mobile small scree
  • 在 Dart 中不继承静态变量的理由是什么?

    In Dart 如果一个类扩展了另一个类 则扩展类继承所有超类的非静态变量 但不继承其任何静态变量 例如 class TestUpper static final String up super String upup 10 class T
  • “DOM 0 方式”检索 HTML 属性值

    jQuery 有一个attr 检索给定 HTML 属性值的方法 例如 var foo document getElementById foo foo attr id 但是 从性能角度来看 这并不是最佳选择 因为必须创建 jQuery 对象才
  • 在 iOS 应用程序中以编程方式获取崩溃报告

    我想在我的应用程序内访问我的应用程序的崩溃报告 并且我需要将崩溃报告发送到服务器 我在 google 中搜索 找不到任何可以帮助我实现目的的 API 但我发现有一些开源项目 例如 QuincyKit plcrashreporter 用于获取
  • Dart 内部的 wait 到底做了什么?

    我正在开发一个需要使用本地存储的颤振应用程序 由于Android中的文档目录路径将在Future中给出 因此每次我想使用该路径时 我都必须检查future是否完成 代码可能类似于下面 class DataStructure late Fut