请教各位大佬,Flutter/dart 中,async 返回的 Future 来源问题,以及什么时候会把 await 后面的代码抛到事件循环里(flutter相关)

发布于 1周前 作者 eggper 来自 Flutter

这是一段测试代码,很多教程里都有

main() {
  print("Main 开始");
  A();
  print("Main 结束");
}

Future<void> A() async { print(“A 开始执行这个方法~”); print(await B()); // print(B()); print(“A 执行结束”); }

Future<String> B() async { print(“B 开始执行这个方法~”); final result = await Future.delayed(Duration(seconds: 3), () => “123”); // final result = await “123”; print(“B 执行结束~”); return Future(() => “请求到的数据:” + result.toString()); }

运行结果:

Main 开始  
A 开始执行这个方法~  
B 开始执行这个方法~  
Main 结束  
B 执行结束~  
请求到的数据:123  
A 执行结束  

问下各位大佬:

  1. 如果一个函数被 async 标记,但内部没有 await ,那么函数内部代码会貌似会同步执行,最后会返回 Future ,这个 Future 是怎么来的?

  2. 在 A 函数中不使用 await 调用 B 函数(A 函数的注释行),在遇到 B 函数的 Future.delay 时直接返回了 Future 对象给 A ,这个返回给 A 的 Future 具体是怎么来的?

  3. 通过执行结果,并不是所有遇到 await 函数就把当前函数的后半部分抛到 event_looper 里,因为 await 调用 B 函数后,还是会同步调用 B 函数第一行打印语句。那么究竟是什么情况会导致 await 后面的抛到 event_looper ,是有 Future 对象创建出来的时候么?

  4. 目前 dart 是可以写 await "123" 代码的,这样写自动变成 await Future.value("123") 么?


请教各位大佬,Flutter/dart 中,async 返回的 Future 来源问题,以及什么时候会把 await 后面的代码抛到事件循环里(flutter相关)

更多关于请教各位大佬,Flutter/dart 中,async 返回的 Future 来源问题,以及什么时候会把 await 后面的代码抛到事件循环里(flutter相关)的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

3 回复
  1. JS 的 async 会将返回结果自动包装为 Future ,Dart 也是类似的原理。异步函数会异步执行,返回结果为 Future 类型,跟里面是否使用 await 没什么关系。

    你所认为的同步,其实只是因为你这测试用例过于简单,只有 A,B ,给你带来的错觉。

    2. 你为什么会认为“遇到 B 函数的 Future.delay 时直接返回了 Future 对象给 A”,你用打印下结果就知道不是你想得那样:
    //修改 A 函数的 print(B());为:
    var result = B();
    result.then((value) => print(value));

    3. await 有两个作用:1. 让“await doSomething()”的 doSomething()异步执行( JS,DART 就是“抛事件循环”,其它语言可能就是多线程、协程等) 2. 等待 doSomething()对应的异步任务执行完成,然后再执行剩余部分。所以只有 B 执行完后,才返回执行 A 的后半部分,也就是你说的“同步调用 B 函数第一行打印语句”。

    “抛事件循环”,是一种抽象化的模型,容易让人理解得云里雾里。沿用这种模型来说明,应该是先抛 B()到事件循环,再抛 A 的剩余部分到事件循环。

    事实上,当 JS 和 Dart 的代码混合了异步逻辑,很难只用事件模型来描述代码的执行情况。比如,假设 B()函数里面await C(),那 C()是不是就抛到 A 的剩余部分后面了,岂不是 A 的剩余部分还先于 C()执行。当然,你可以再给这个模型补充很多细节,问题是这些细节就牵涉到具体的实现,比如 chrome,mozilla,quickjs 等完全可以采用不同的底层实现。

    这并不是说事件模型是错误的,只是说当存在异步逻辑时,事件模型需要补充很多细节,不然就会像你一样陷入混乱,此时可以不用事件模型来理解程序的执行。

    4. 不了解,我这里 IDE 提示:“可以去掉 await ,且 await 无效”。无论是还是不是,这种代码没有啥实际价值。

更多关于请教各位大佬,Flutter/dart 中,async 返回的 Future 来源问题,以及什么时候会把 await 后面的代码抛到事件循环里(flutter相关)的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


补充:
1. “函数内部代码会貌似会同步执行”,我理解了,你指的内部代码会作为一个整体被执行,这是正确的。返回 Future 是语法层面的规定,表示这个异步函数的异步执行情况。正如我上面所说的,返回结果会自动包装为 Future ,比如 B 函数,熟练以后是这样:

dart<br>//省略上面内容<br>return "请求到的数据:" + result.toString();<br>

在Flutter/Dart中,关于async返回的Future来源及await后代码的处理机制,以下是我的专业解答:

首先,async关键字用于标记一个函数为异步函数,该函数在执行过程中可能会进行耗时操作(如网络请求)。这些异步操作不会立即完成,因此async函数会返回一个Future对象,该对象代表了一个可能在未来某个时间点完成的结果。这个Future对象是由Dart运行时自动创建的,用于封装异步操作的结果。

其次,当在async函数内部使用await关键字时,它会暂停当前异步函数的执行,直到等待的Future对象完成。在这个过程中,await后面的代码实际上并没有被“抛到事件循环里”,而是被挂起等待Future的完成。一旦Future完成,await后面的代码才会继续执行。

在Flutter的事件循环机制中,Future对象及其回调函数的处理遵循Dart的异步模型。Future对象会被添加到事件队列中,等待Dart的事件循环调度执行。当事件循环处理到该Future对象时,会触发其相关的回调函数(如then或catchError中注册的回调),从而继续执行await后面的代码。

综上所述,async返回的Future由Dart运行时创建,而await后的代码在Future完成时继续执行,这一过程由Flutter/Dart的事件循环机制管理。

回到顶部