【Flutter】Flutter 异步方法调用 ( async 和 await 关键字解析 | Dart 单线程 | await 调用方式对比 | Future<void> 返回值作用 )
文章目录
- 一、错误记录
- 二、原理分析
- 1、报错分析
- 2、async 和 await 关键字解析
- 3、Dart 单线程
- 4、await 调用方式对比
- 使用 await 关键字调用
- 不使用 await 关键字调用
- 5、Future\<void> 返回值作用
- 三、解决方案
- 1、方案 1 : 方法加上 async
- 2、方案 2 : 调用去掉 await
一、错误记录
编译 Flutter 应用时 , 报如下错误 :
D:\002_Project\001_Flutter\client_terminal>flutter build apk--debugFlutterassets will be downloaded from https://storage.flutter-io.cn.Makesure you trustthissource!Flutterassets will be downloaded from https://storage.flutter-io.cn.Makesure you trustthissource!lib/pages/login_page.dart:38:5:Error:'await'can only be usedin'async'or'async*'methods.awaitLoginController().login(context,_accountController.text,_passwordController.text);// 调用登录方法 , 传入账号和密码^^^^^Targetkernel_snapshot_program failed:ExceptionFAILURE:Buildfailedwithan exception.*Whatwent wrong:Executionfailedfortask':app:compileFlutterBuildDebug'.>Process'command 'D:\001_Develop\026_Flutter_3.41.7\flutter\bin\flutter.bat''finishedwithnon-zero exit value1*Try:>Runwith--stacktrace option togetthe stack trace.>Runwith--info or--debug option togetmore log output.>Runwith--scan togetfull insights.>Getmore help at https://help.gradle.org.BUILD FAILEDin10sRunningGradletask'assembleDebug'...10.7sGradletask assembleDebug failedwithexit code1D:\002_Project\001_Flutter\client_terminal>二、原理分析
1、报错分析
报错问题 :
Error:'await'can only be usedin'async'or'async*'methods.报错原因是在一个「普通方法 / 按钮点击」里写了 await ,但这个方法没有加 async 关键字 ;
await 必须配合 async 一起用, 否则 Dart 直接报错 ;
- async 是" 声明这是一个异步方法 " ;
- await 是" 等待这个异步任务执行完 " ;
- await只能在 async 方法里用 , 否则报错 ;
2、async 和 await 关键字解析
Dart 是单线程语言 , 不能真正阻塞 , 所以用 异步 + 事件循环 实现不卡顿 ;
- async 关键字 :把方法包装成异步任务 ;
- await 关键字 :暂停当前方法 , 不阻塞主线程 , 等任务完成后再恢复执行 ;
表面看像同步代码 , 底层实际是异步非阻塞执行 ;
async 关键字 作用 :告诉 Dart 这个方法里面有异步操作 , 不能立刻执行完 ;
- 加了 async , 方法就变成异步方法
- 异步方法自动返回 Future
- 只有加了它 , 里面才能写 await
await 关键字 作用 :等待后面的异步任务执行完成 , 再继续往下走 ;
- 等待网络请求
- 等待文件读写
- 等待数据库操作
- 等待延时
3、Dart 单线程
Dart 永远是单线程 , 不会卡住 , 但它有一个机制 :
- 遇到耗时操作 ( await ) , 就先挂起 , 去干别的事
- 耗时操作做完 , 再回来继续执行
- 它不会阻塞线程 , 但可以 " 等待任务结果 " ;
两个写法都是单线程 , 但执行结果完全不一样 ;
await doSomething();→会等待 , 等里面的异步任务 ( 网络请求 / 延时 ) 真正做完 , 才继续往下走 ;doSomething();→不会等待 , 直接立刻往下执行 , 异步任务在后台自己慢慢跑 ;
4、await 调用方式对比
调用下面的方法 :
Future<void>doSomething()async{awaitFuture.delayed(Duration(seconds:2));// 模拟耗时2秒print("任务完成");}使用 await 关键字调用
使用
print("开始");awaitdoSomething();// 等待2秒print("结束");方式 , 进行调用 , 得到的结果 :
开始(等待2秒)任务完成 结束不使用 await 关键字调用
使用
print("开始");doSomething();// 不等待 , 直接跳过print("结束");方式执行 , 结果
开始 结束(2秒后)任务完成5、Future<void> 返回值作用
Future<void> 这个返回值的真正作用=让外部能「等待」这个方法执行完 ;
- 没有它 , 你就不能用 await ;
- 不能用 await , 你就无法控制执行顺序 ;
Future<void>不是 " 返回内容 " ,而是一个「任务凭证 / 任务小票」 ;
- void = 没有实际数据返回 ( 不 return 任何值 ) ;
- Future = 代表一个异步任务 , 可以被等待 ;
await 只能等待 Future 返回值类型的函数 :
- 你给它 void → 它不认识 , 无法等待 ;
- 你给它 Future → 它认识 , 可以等待 ;
三、解决方案
1、方案 1 : 方法加上 async
方案 1 : 给方法加上 async ( 最常用、最标准 )
Future<void>_handleLogin()async{awaitLoginController().login(username,password);}2、方案 2 : 调用去掉 await
方案 2 : 如果不需要等待 , 直接去掉 await ;
void_handleLogin(){LoginController().login(username,password);}