当前位置: 首页>>代码示例 >>用法及示例精选 >>正文


Dart Future用法及代码示例


dart:async 库中Future 类的用法介绍如下。

异步计算的结果。

asynchronous computation 在启动时不能立即提供结果,这与同步计算不同,同步计算通过返回值或抛出来立即计算结果。异步计算可能需要等待程序外部的某些事情(读取文件、查询数据库、获取网页),这需要时间。在结果可用之前,异步计算不会阻塞所有计算,而是立即返回一个Future,它将与结果一起eventually"complete"。

异步编程

要执行异步计算,请使用 async 函数,该函数始终会产生未来。在这样的异步函数中,您可以使用await 操作来延迟执行,直到另一个异步计算有结果。在等待函数的执行被延迟的同时,程序并没有被阻塞,可以继续做其他事情。

例子:

import "dart:io";
Future<bool> fileContains(String path, String needle) async {
   var haystack = await File(path).readAsString();
   return haystack.contains(needle);
}

这里来自 dart:ioFile.readAsString 方法是一个返回 Future<String> 的异步函数。 fileContains 函数在其主体之前标有async,这意味着您可以在其中使用await,并且它必须返回一个未来。对File(path).readAsString() 的调用启动将文件读入字符串并生成最终包含结果的Future<String>。然后 await 等待该未来以字符串完成(或错误,如果读取文件失败)。在等待期间,程序可以做其他事情。当 future 以字符串结束时,fileContains 函数计算一个布尔值并返回它,然后完成它在第一次调用时返回的原始未来。

如果未来以 error 完成,则等待该未来将(重新)抛出该错误。在这里的示例中,我们可以添加错误检查:

import "dart:io";
Future<bool> fileContains(String path, String needle) async {
  try {
    var haystack = await File(path).readAsString();
    return haystack.contains(needle);
  } on FileSystemException catch (exception, stack) {
    _myLog.logError(exception, stack);
    return false;
  }
}

您使用普通的 try /catch 来捕获等待的异步计算的失败。

一般来说,在编写异步代码时,你应该总是等待一个未来的产生,而不是等到另一个异步延迟之后。这可确保您准备好接收未来可能产生的任何错误,这一点很重要,因为 no-one 正在等待的异步错误是 uncaught 错误,并且可能会终止正在运行的程序。

使用Future API 进行编程。

Future 类还提供了更直接的低级函数来访问它完成的结果。 asyncawait 语言特性建立在此函数之上,有时直接使用它是有意义的。有些事情你不能通过一次await ing 一个未来来完成。

使用 Future ,您可以手动注册处理值或错误的回调(一旦可用)。例如:

Future<int> future = getFuture();
future.then((value) => handleValue(value))
      .catchError((error) => handleError(error));

由于 Future 可以通过两种方式完成,使用值(如果异步计算成功)或错误(如果计算失败),您可以为其中一种或两种情况安装回调。

在某些情况下,我们说未来已完成 with another future 。这是一种简短的方式来说明未来以相同的方式完成,具有相同的值或错误,一旦另一个未来本身完成,另一个未来。完成未来的平台库中的大多数函数(例如 Completer.completeFuture.value )也接受另一个未来,并自动处理将结果转发到正在完成的未来。

注册回调的结果本身就是一个 Future ,它反过来通过使用原始未来结果调用相应回调的结果来完成。如果调用的回调抛出,则新的未来完成并出现错误。例如:

Future<int> successor = future.then((int value) {
    // Invoked when the future is completed with a value.
    return 42;  // The successor is completed with the value 42.
  },
  onError: (e) {
    // Invoked when the future is completed with an error.
    if (canHandle(e)) {
      return 499;  // The successor is completed with the value 499.
    } else {
      throw e;  // The successor is completed with the error e.
    }
  });

如果未来在完成错误时没有任何注册的处理程序,它会将错误转发到“uncaught-error 处理程序”。此行为可确保不会以静默方式丢弃任何错误。但是,这也意味着应该尽早安装错误处理程序,以便它们在未来完成时出现错误。以下示例演示了这个潜在的错误:

var future = getFuture();
Timer(const Duration(milliseconds: 5), () {
  // The error-handler is not attached until 5 ms after the future has
  // been received. If the future fails before that, the error is
  // forwarded to the global error-handler, even though there is code
  // (just below) to eventually handle the error.
  future.then((value) { useValue(value); },
              onError: (e) { handleError(e); });
});

注册回调时,分别注册两个回调通常更具可读性,首先使用带有一个参数(值处理程序)的then,然后使用第二个catchError 来处理错误。它们中的每一个都会将它们不处理的结果转发给它们的后继者,它们一起处理值和错误结果。它还具有 catchError 处理 then 值回调中的错误的额外好处。使用顺序处理程序而不是并行处理程序通常会导致代码更容易推理。它还使异步代码与同步代码非常相似:

// Synchronous code.
try {
  int value = foo();
  return bar(value);
} catch (e) {
  return 499;
}

基于期货的等效异步代码:

Future<int> asyncValue = Future(foo);  // Result of foo() as a future.
asyncValue.then((int value) {
  return bar(value);
}).catchError((e) {
  return 499;
});

与同步代码类似,错误处理程序(使用 catchError 注册)正在处理由 foobar 引发的任何错误。如果 error-handler 已注册为 then 调用的 onError 参数,则它不会捕获来自 bar 调用的错误。

期货可以注册多个callback-pair。每个后继者都被独立对待,并被视为唯一的后继者。

未来也可能永远无法完成。在这种情况下,不会调用回调。如果可能的话,通常应该避免这种情况,除非它有非常清楚的记录。

可用的扩展

FutureExtensions

相关用法


注:本文由纯净天空筛选整理自dart.dev大神的英文原创作品 Future<T> class。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。