• 作者:老汪软件技巧
  • 发表时间:2024-08-31 10:02
  • 浏览量:

众所周知,在 Flutter 中,await 是用来等待异步操作完成的关键字。它不会阻塞主线程,而是通过 Dart 的事件循环和 Future 对象的机制来实现异步代码的暂停与恢复。

当我们在使用await时候通常需要在函数名后面添加async关键字做标记,那么添加了aysnc后,flutter编译器或者说是flutter运行时做了些什么事情呢?

程序在 await 的异步操作完成后,会回到原先暂停的代码处并继续执行,那么flutter是如何保存这个代码恢复节点的?

带着这两个问题,我们寻找一下答案:

在 Flutter(和 Dart)中,当代码执行到 await 时,程序会暂停当前异步函数的执行,等待 Future 完成,然后在完成后继续执行。为了实现这种行为,Dart 语言使用了一种称为“状态机”(state machine)的机制来记录和管理代码执行的暂停点和恢复点。

状态机的工作原理

异步函数的转换:

状态保存:

事件循环与恢复执行:

恢复执行:

例子:状态机如何处理异步函数

考虑一个简单的异步函数:


Future<void> exampleFunction() async {
  print('Start');
  await Future.delayed(Duration(seconds: 2));
  print('End');
}

当 Dart 编译器看到这个函数时,它会将其转换为类似下面的状态机代码(伪代码):

class _ExampleFunctionStateMachine {
  int _state = 0;//默认状态为0
  Future<void> run() async {
    switch (_state) {
      case 0:
        print('Start');
        _state = 1;//将状态修改为1
        return Future.delayed(Duration(seconds: 2)).then((_) => run());//执行完异步任务后重新调用run方法
      case 1:
        print('End');
        return Future.value();
    }
  }
}

在这个转换后的代码中:

编译时和运行时

将异步函数转换为状态机的过程是在 编译时 完成的,而不是在运行时。具体来说,当你编写一个使用 async/await 的 Dart 函数时,Dart 编译器在编译代码时会将该函数转换为一个状态机,这样在运行时可以管理异步操作的暂停和恢复。

编译时的状态机转换运行时的执行优势总结

Dart 使用状态机来管理异步函数的暂停和恢复。await 触发状态机记录当前执行状态,并在异步操作完成后恢复执行。这个机制确保了异步函数的执行看起来是顺序的,但实际上是通过非阻塞的方式在不同的状态间切换。状态机记录了每个暂停点(代码节点),并在异步操作完成后恢复执行原来的代码。

将异步函数转换为状态机的过程是在编译时完成的。编译器在编译过程中会分析和转换这些函数,使得在运行时,代码可以通过状态机来有效地管理异步操作的暂停和恢复。这种编译时的转换提高了代码的执行效率,同时让开发者的代码保持简单和易读。

尽管 Dart 官方文档没有直接使用“状态机”这一术语,但该术语可以帮助理解编译器和虚拟机如何处理异步操作的机制dart.dev/libraries/a…