我啥时候需要将异步函数的返回类型声明为未来对象?
Posted
技术标签:
【中文标题】我啥时候需要将异步函数的返回类型声明为未来对象?【英文标题】:When do I need to state the return type of an async function as a future object?我什么时候需要将异步函数的返回类型声明为未来对象? 【发布时间】:2019-10-24 11:57:44 【问题描述】:我正在上一堂关于 Dart 异步编程的课程,但由于某种原因,我有点困惑。我想我理解了当异步函数可能需要一些时间时应该如何使用它的概念,因此您可以使用异步函数而不是阻塞和冻结您的应用程序,以便执行下一个代码块或方法以及何时执行异步函数完成或准备执行。 (如果我的理解有缺陷,请告诉我)
但是,我并没有真正理解 Future 部分。我知道它可以用作异步函数的返回类型,因为本质上你是说该函数现在返回一个未来对象,但让我们在它完成后回到它。但是我的导师有点让我困惑,有时她有一个未来作为返回类型,而另一次她没有把它说出来,它们都是异步函数。所以现在我很难理解什么时候有必要明确声明 Future 返回类型,即使它是无效的?另外,不只是使用异步并等待一个函数已经创建了一个未来的对象吗?非常感谢任何澄清,谢谢。
【问题讨论】:
你能举一些你遇到问题的代码示例 【参考方案1】:是的,使用 async 关键字将使函数自动返回 Future。
即使对于 void 函数,显式声明函数的返回类型总是更好,否则,编译器会将函数解释为具有动态返回类型。
它还将帮助/使读者更容易了解函数的返回类型。
此外,您需要将对象包装在 Future 中的异步函数中,如下所示:
Future<Object> getObject() async
final object = await timeConsumingTask();
return object;
如果你不包装就这样写:
Object getObject() async
final object = await timeConsumingTask();
return object;
编译器抛出错误:Functions marked 'async' must have a return type assignable to 'Future'.
对于 void 函数,您似乎不必将返回类型包装在 Future 中,因此可以这样:
void doSomething() async
await timeConsumingTask();
print('done');
【讨论】:
好的,所以本质上使用 futureawait authenticateUser(); goToNextScreen;
'await' 关键字基本上意味着除非完成耗时的任务,否则不会执行下一行。当下一行依赖于需要以耗时方式获取的对象时,这尤其有用。【参考方案2】:
让我们考虑一个方法gatherNewsReports()
,它只返回一个Future<String>
。来自gatherNewsReports
的Future
的字符串值。实现gatherNewsReports
。
// Imagine this is a slow method. Takes time to finish
Future<String> gatherNewsReports() => Future.delayed(Duration(seconds: 1), () => news);
我们将遍历所有可能的方法调用与Future
和async
的组合。我要做的方法叫getDailyNewsDigest
选项一:
方法的一个定义可能与方法调用中给出的Future
和async
一样:
Future<String> getDailyNewsDigest() async
var str = await gatherNewsReports();
print(str);
return str;
请记住 gatherNewsReports()
返回一个 Future<String>
。我们只是返回 gatherNewsReports
返回的任何内容。
用法:
main() async
await getDailyNewsDigest();
print('call done');
输出:
<gathered news goes here>
call done
评论:这似乎是直截了当的。您只需调用该方法并等待它。请记住,当从 main
方法调用 getDailyNewsDigest
时,我们使用了 await
关键字。因此,除非我们通过1 second
,即它需要Future
执行的持续时间。如果我们不使用 await 关键字,那么输出序列将被反转。
选项 2
方法的一个定义可能与在方法调用中给出的Future
和async
NOT 一样:
Future<String> getDailyNewsDigest()
var str = await gatherNewsReports();
print(str);
return str;
这是无效的,因为您不能使用await
调用方法,在本例中为gatherNewsReports
。 这是无效的。
选项-3
我们定义的方法可能是在方法调用中给出的Future
NOT GIVEN 和async
。由于返回类型将是 void
,我们将不会返回任何内容(注意:如果我们尝试返回除 Future
或 void
之外的任何内容,则会收到错误):
void getDailyNewsDigest() async
var str = await gatherNewsReports();
print(str);
这是一个有效的方法定义。现在,由于该方法被声明为void
,我们不能在main
方法上使用await
。更新的main
方法。
main() async
getDailyNewsDigest(); // We can't await on it since return is void
print('call done');
输出:
call done
<gathered news goes here>
正如您所见,由于没有await
就不会调用方法getDailyNewsDigest
,因此输出是相反的。我们不再等待getDailyNewsDigest
完成。
选项-4
我们定义的方法可能是Future<Void>
,而不是方法调用中给出的Future<String>
和async
:
Future<void> getDailyNewsDigest() async
var str = await gatherNewsReports();
print(str);
return;
现在在我们的 main 方法中,我们可以再次使用 await
关键字来调用 getDailyNewsDigest
。
main() async
await getDailyNewsDigest(); // We can await on it since return is Future<Void> but don't care on the output since it returns nothing
print('call done');
这是我能想到的 4 种组合。
至于这个:
但是我的导师有点让我困惑,有时她的未来是 返回类型和另一次她没有说,他们都是 异步函数。
用Future
声明一个方法意味着你可以等待它,用void
声明它意味着你不能在其中await
。如果您不想对Future
的输出做任何事情,您当然可以选择不在Future
上使用await
。如果您以不希望任何人依赖该方法的输出的方式编写代码,即,否则我们将从该方法返回的 Future
将自行处理 d,我们关心的是启动并继续我们的工作;在这种情况下,我们应该使用返回类型 void
来定义我们的方法。
【讨论】:
好的,但是当你说如果你用 void 声明它然后你不能等待它是什么意思。显然,一个带有 await 的 void 异步函数会等待 await 之后包含的部分在继续执行该函数之前发生?如果函数是用 async 定义的,这意味着序列中的下一个函数将开始工作,而 async 函数也正常工作?您能否详细解释一下使用异步函数如何影响执行的函数流? 如果声明方法,假设myMethod
为void myMethod() async
,那么在main方法中不能做await myMethod()
,只能做myMethod()
。您当然可以从 INSIDE 方法执行await
功能,因为您声明它等待,但您永远不能使用await
从外部调用该方法。因此,如果您只调用此方法,那么 main 方法将按原样运行,而无需等待异步函数完成。
将方法声明为async
不会改变代码流。只有你await
才可以。查看选项1和3的输出。输出是相反的,唯一的区别是我没有从main方法中调用await
。以上是关于我啥时候需要将异步函数的返回类型声明为未来对象?的主要内容,如果未能解决你的问题,请参考以下文章
vue3异步组件(defineAsyncComponentSuspense的使用)
我啥时候需要使用 super(props) 将 prop 传递给 react 组件的构造函数? [复制]