为啥在 dart/flutter 中不等待 await 返回就执行代码?
Posted
技术标签:
【中文标题】为啥在 dart/flutter 中不等待 await 返回就执行代码?【英文标题】:Why does the code execute without waiting for await to return in dart/flutter?为什么在 dart/flutter 中不等待 await 返回就执行代码? 【发布时间】:2021-06-25 18:18:14 【问题描述】:我正在开发一个移动应用程序。 我正在使用云功能来完成注册过程。 以下是我的代码的简化可重现示例:- 飞镖文件:-
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:cloud_functions/cloud_functions.dart';
void main() => runApp(MaterialApp(home: Test()));
class Test extends StatefulWidget
const Test(
Key key,
) : super(key: key);
@override
State<StatefulWidget> createState() => TestState();
class TestState extends State<Test>
@override
Widget build(BuildContext context)
return Scaffold(
backgroundColor: Colors.grey,
appBar: AppBar(
title: Text('Hi,',style: GoogleFonts.pacifico(fontSize: 25),),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children:<Widget> [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children:<Widget>[
Padding(padding:const EdgeInsets.all(8)),
ElevatedButton(
onPressed:()
enroll.call("Password", "email@gmail.com", "name");
,
child:Padding(
padding: const EdgeInsets.all(12.0),
child: Text('TEST',style: TextStyle(fontSize: 20.0),)
),
),
],
),
],
),
);
Future<void> enroll(String pass,String email,String name) async
HttpsCallable register = FirebaseFunctions.instanceFor(region: 'asia-south1').httpsCallable('Register');
final funcCall = await register.call(
<String, dynamic>
'pass': pass,
'email': email,
'Name': name,
);
String result = funcCall.data;
print(result);
Firebase 功能代码为:-
import * as functions from "firebase-functions";
const admin = require('firebase-admin');
admin.initializeApp();
exports.Register = functions.region('asia-south1').https.onCall(async (data,context)=>
const pass = data.pass;
const Name = data.name;
const email = data.email;
await admin.auth()
.createUser(
email: email,
emailVerified: false,
password: pass,
displayName: Name,
disabled: false,
)
.then(() =>
console.log("done")
return "done"
)
.catch((error: any) =>
console.error(error.code);
return error.code
);
);
上次执行期间的 Firebase 控制台日志如下:-
->10:54:37.099 AM
Register
Function execution took 662 ms, finished with status code: 200
->10:54:37.095 AM
Register
auth/email-already-exists
->10:54:36.438 AM
Register
Function execution started
调试日志是:-
I/ViewRootImpl@3af8d1b[MainActivity]( 5889): ViewPostIme pointer 0
I/ViewRootImpl@3af8d1b[MainActivity]( 5889): ViewPostIme pointer 1
W/ckerbin.atchec( 5889): Accessing hidden method Lcom/android/org/conscrypt/ConscryptEngineSocket;->setUseSessionTickets(Z)V (greylist-max-q,core-platform-api, reflection, denied)
W/ckerbin.atchec( 5889): Accessing hidden method Lcom/android/org/conscrypt/OpenSSLSocketImpl;->setUseSessionTickets(Z)V (greylist-max-q,core-platform-api, reflection, denied)
W/ckerbin.atchec( 5889): Accessing hidden method Lcom/android/org/conscrypt/AbstractConscryptSocket;->setUseSessionTickets(Z)V (greylist-max-q, reflection, denied)
W/ckerbin.atchec( 5889): Accessing hidden method Lcom/android/org/conscrypt/ConscryptEngineSocket;->setHostname(Ljava/lang/String;)V (greylist-max-q,core-platform-api, reflection, denied)
W/ckerbin.atchec( 5889): Accessing hidden method Lcom/android/org/conscrypt/OpenSSLSocketImpl;->setHostname(Ljava/lang/String;)V (greylist-max-q,core-platform-api, reflection, denied)
W/ckerbin.atchec( 5889): Accessing hidden method Lcom/android/org/conscrypt/AbstractConscryptSocket;->setHostname(Ljava/lang/String;)V (greylist-max-q, reflection, denied)
W/ckerbin.atchec( 5889): Accessing hidden method Lcom/android/org/conscrypt/OpenSSLSocketImpl;->setAlpnProtocols([B)V (greylist-max-q,core-platform-api, reflection, denied)
W/ckerbin.atchec( 5889): Accessing hidden method Lcom/android/org/conscrypt/AbstractConscryptSocket;->setAlpnProtocols([B)V (greylist-max-q, reflection, denied)
W/ckerbin.atchec( 5889): Accessing hidden method Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getAlpnSelectedProtocol()[B (greylist-max-q,core-platform-api, reflection, denied)
W/ckerbin.atchec( 5889): Accessing hidden method Lcom/android/org/conscrypt/AbstractConscryptSocket;->getAlpnSelectedProtocol()[B (greylist-max-q, reflection, denied)
I/flutter ( 5889): null
这两个代码都是实际代码的简化版本,所以请不要说为什么要为此使用云功能..
【问题讨论】:
你能提供一个简化但可重现的例子吗? 好的,我会改写问题 我已经用可重现的代码更改了完整的问题。 您好,您是否在 firebase 函数中尝试过await admin.auth()
而不是 return admin.auth()
?这就是文档设置示例以返回承诺的方式。 firebase.google.com/docs/functions/…
它也无济于事
【参考方案1】:
仔细查看您的 Firebase 函数,我发现了两个问题:
-
在同一函数中同时使用
await
和 then
关键字。这两个语句做同样的事情。引用此accepted answer。
await
只是.then()
的内部版本(基本上做同样的事情)。选择其中之一的原因与所需的编码风格或编码便利性有关。当然,解释器有更多的机会来优化事物 在内部使用 await,但您不太可能决定使用哪个。
换句话说,同时使用它们是一种开销。
-
下一段代码仅在
then
嵌套 Promise 的上下文中返回结果,这与云函数寄存器的上下文不同。换句话说,您在颤振中收到一个空值,因为云函数在其运行上下文中没有返回任何内容。
.then(() =>
console.log("done")
return "done"
)
.catch((error: any) =>
console.error(error.code);
return error.code
正如我之前提到的,then
和 await
用于相同目的,因此您有两个选项来更正代码。
你可以使用await
:
exports.Register = functions.https.onCall(async (data, context) =>
[...]
try
await admin.auth()
.createUser(
email: email,
emailVerified: false,
password: pass,
displayName: Name,
disabled: false,
);
return "user successfully registered";
catch (error)
console.log(error);
return "the function failed;check Cloud Logging for the reason";
或者你可以使用then
:
exports.RegisterThen = functions.https.onCall((data, context) =>
[...]
return admin.auth()
.createUser(
email: email,
emailVerified: false,
password: pass,
displayName: Name,
disabled: false,
)
.then(() => return "user successfully registered")
.catch(error =>
console.log(error);
return "the function failed;check Cloud Logging for the reason";
);
请注意,当我使用 await
时,函数是如何用 async
定义的,如果我使用 Promises 中的 then
函数,async
是如何不使用的。
希望对你有用
【讨论】:
成功了!从现在开始我会牢记这一点以上是关于为啥在 dart/flutter 中不等待 await 返回就执行代码?的主要内容,如果未能解决你的问题,请参考以下文章
Dart / Flutter:错误“流已被收听。” fa“for循环”中的&&“等待”失败
Dart/Flutter:当作为参数传递时,List 中的元素字符串变为空(为啥??)
为啥 build_runner 在 dart/flutter 中序列化 JSON 时不生成文件