我什么时候需要将异步函数的返回类型声明为未来对象?

Pot*_*ato 9 future async-await dart flutter

我正在学习有关使用 Dart 进行异步编程的课程,但出于某种原因,我有点困惑。我想我理解您应该如何使用异步函数的概念,当它可能需要一些时间时,而不是阻塞和冻结您的应用程序,而是使用异步函数,以便执行下一个代码块或方法,以及何时执行异步函数完成或准备好执行。(如果我的理解有缺陷,请告诉我)

但是,我并没有真正了解 Future<> 部分。我知道它可以用作异步函数的返回类型,因为本质上你是说该函数现在返回一个未来的对象,但让我们在它完成后回到它。但是我的导师有点让我困惑,有时她有一个 future 作为返回类型,而另一次她没有把它放在那里,它们都是异步函数。所以现在我很难理解什么时候需要明确声明 Future 返回类型,即使它是无效的?也不只是使用 async 并等待一个函数已经创建了一个未来的对象吗?非常感谢任何澄清,谢谢。

Gar*_* AP 11

是的,使用 async 关键字将使函数自动返回一个 Future。

即使对于 void 函数,显式声明函数的返回类型总是更好,否则编译器会将函数解释为具有动态返回类型。

它还将帮助/使读者更容易了解函数的返回类型。

此外,您需要将对象包装在 Future 中的异步函数中,如下所示:

Future<Object> getObject() async {
  final object = await timeConsumingTask();
  return object;
}
Run Code Online (Sandbox Code Playgroud)

如果你这样写而不包装它:

Object getObject() async {
  final object = await timeConsumingTask();
  return object;
}
Run Code Online (Sandbox Code Playgroud)

编译器抛出错误: Functions marked 'async' must have a return type assignable to 'Future'.

对于 void 函数,似乎您不必将返回类型包装在 Future 中,所以这样的事情很好:

void doSomething() async {
  await timeConsumingTask();
  print('done');
}
Run Code Online (Sandbox Code Playgroud)

  • 好吧,本质上来说,当函数不返回任何内容时,使用 future&lt;void&gt; 和仅使用 void 没有什么区别。只是为了澄清一下,只要我有一项耗时的任务,并且我希望序列中的下一个函数在后台工作时继续执行,我就应该使用异步函数,对吗?或者,如果我想使用 firebase 对用户进行身份验证,那么我是否也应该使用异步函数,这样我就不想继续,直到用户得到正确的身份验证?使用异步会跳过并转到下一个函数吗?我刚刚看到那些使用这种格式的函数。 (2认同)

Sha*_*rim 7

让我们考虑一个gatherNewsReports()只返回 a的方法Future<String>Futurefrom的字符串值gatherNewsReports。的实施gatherNewsReports

// Imagine this is a slow method. Takes time to finish
Future<String> gatherNewsReports() => Future.delayed(Duration(seconds: 1), () => news);
Run Code Online (Sandbox Code Playgroud)

我们将使用Future和进行方法调用的所有可能组合async。我要做的方法叫做getDailyNewsDigest

选项1:

该方法的一个定义可能是与Futureasync在方法调用给出:

Future<String> getDailyNewsDigest() async {
  var str = await gatherNewsReports();
  print(str);
  return str;
}
Run Code Online (Sandbox Code Playgroud)

请记住gatherNewsReports()返回 a 的那个Future<String>。我们只是返回任何gatherNewsReports回报。

用法:

main() async {
  await getDailyNewsDigest();
  print('call done');
}
Run Code Online (Sandbox Code Playgroud)

输出:

<gathered news goes here>
call done
Run Code Online (Sandbox Code Playgroud)

评论:这看起来很简单。您只需调用该方法并等待它。请记住,我们awaitgetDailyNewsDigestmain方法调用时使用了关键字。所以,除非我们通过1 second,即它需要Future执行的持续时间。如果我们没有使用 await 关键字,那么输出顺序将被颠倒。

选项 2

该方法的一种定义可能与方法调用中的Futuregiven 和async NOT given 相同:

Future<String> getDailyNewsDigest() {
  var str = await gatherNewsReports();
  print(str);
  return str;
}
Run Code Online (Sandbox Code Playgroud)

这是无效的,因为await在这种情况下,您不能使用 调用方法gatherNewsReports这是无效的

选项 3

我们定义的方法可能是Future NOT GIVENasync在方法调用中给出。由于返回类型将是void我们不会返回任何内容(注意:如果我们尝试返回 aFuture或 a以外的任何内容,void则会出现错误):

void getDailyNewsDigest() async {
  var str = await gatherNewsReports();
  print(str);
}
Run Code Online (Sandbox Code Playgroud)

这是一个有效的方法定义。现在,由于方法被声明为void我们不能awaitmain方法上。更新的main方法。

main() async {
  getDailyNewsDigest(); // We can't await on it since return is void
  print('call done');
}
Run Code Online (Sandbox Code Playgroud)

输出:

call done
<gathered news goes here>
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,因为在getDailyNewsDigest没有await反转输出的情况下不会调用该方法。我们不再等待getDailyNewsDigest完成。

选项 4

我们定义的方法可能是用Future<Void>的,而不是Future<String>async在方法调用给出:

Future<void> getDailyNewsDigest() async {
  var str = await gatherNewsReports();
  print(str);
  return;
}
Run Code Online (Sandbox Code Playgroud)

现在在我们的 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');
}
Run Code Online (Sandbox Code Playgroud)

这是我能想到的4种组合。

至于这个:

但是我的导师有点让我困惑,有时她有一个 future 作为返回类型,而另一次她没有把它放在那里,它们都是异步函数。

声明一个方法Future意味着你可以等待它,声明它void意味着你不能await在它里面。你当然也可以选择不awaitFuture,如果你不介意做的输出任何东西Future。如果您以不希望任何人依赖该方法的输出的方式编写代码,即,Future否则我们将从该方法返回的 d 将自行处理,我们所关心的只是触发它- 并-继续我们的工作;在这种情况下,我们应该使用返回类型定义我们的方法void