V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
SmaliYu
V2EX  ›  Flutter

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

  •  1
     
  •   SmaliYu · 65 天前 · 638 次点击
    这是一个创建于 65 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    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") 么?

    2 条回复    2024-02-22 22:59:13 +08:00
    CLMan
        1
    CLMan  
       65 天前
    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 无效”。无论是还是不是,这种代码没有啥实际价值。
    CLMan
        2
    CLMan  
       65 天前
    @CLMan 补充:
    1. “函数内部代码会貌似会同步执行”,我理解了,你指的内部代码会作为一个整体被执行,这是正确的。返回 Future 是语法层面的规定,表示这个异步函数的异步执行情况。正如我上面所说的,返回结果会自动包装为 Future ,比如 B 函数,熟练以后是这样:

    ```dart
    //省略上面内容
    return "请求到的数据:" + result.toString();
    ```
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1094 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 18:18 · PVG 02:18 · LAX 11:18 · JFK 14:18
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.