Dart 异步编程之 Future

Future

Future<T> 类,其表示一个 T 类型的异步操作结果。如果异步操作不需要结果,则类型为 Future<void>。也就是说首先Future是个泛型类,可以指定类型。如果没有指定相应类型的话,则Future会在执行动态的推导类型。

工厂方法

1、Future(FutureOr computation())

这个工厂构造函数是 Future 类最基本的构造函数,用于创建一个异步任务。
它接受一个 computation 函数作为参数,并返回一个 Future 对象。
再调用 computation 函数之后,返回的 Future 对象会被赋予 computation 函数的执行结果。

 Future<String> fetchString() {
    return Future(() {
        return 'Hello, world!';
  });
}

fetchString().then((value) => print(value)); // 输出 'Hello, world!'

Future<dynamic> future = Future<dynamic>(() => '棒!';);

future.then((value) => print(value)); // 输出 '棒!!'

在这个示例代码中,我们定义了一个 fetchString 函数,它返回一个 Future 对象,这个 Future 对象通过 Future 的基本构造函数来创建。在 computation 函数中,我们返回了一个字符串 ‘Hello, world!’,这个字符串最终会被作为 Future 对象的值返回。在最后,我们使用了 then 方法来处理 Future 对象的值,输出了 ‘Hello, world!’。

需要注意的是,Future 对象的基本构造函数并不会自动执行 computation 函数,而是在 Future 对象被调用 then 方法时才会执行。如果 computation 函数抛出了异常,那么 Future 对象将会变成一个 error 状态的 Future,错误信息会被传递给 then 方法中的错误处理函数或 catch 方法。

另外,由于 computation 函数是异步执行的,所以在 computation 函数执行期间,主线程不会被阻塞。当 computation 函数执行完成后,返回的 Future 对象将会被添加到事件循环队列中,等待被执行。

2、Future.microtask

Future.microtask 方法用于创建一个微任务,它会立即将指定的异步操作加入到微任务队列中,等待下一个事件循环周期执行。它接受一个泛型类型的参数 action,表示异步操作。

Future<String> future = Future.microtask(() => 'Hello, world');

在上面的示例代码中,Future.microtask 方法创建了一个微任务,并将其值设置为 'Hello, world'

2、Future.sync

Future.sync 方法用于创建一个同步执行的 Future 对象。它接受一个参数 compute,表示异步操作的执行体,可以是一个返回结果的同步函数或一个异步函数。示例代码:

Future<String> future = Future.sync(() => 'Hello, World!');
future.then((String value) {
    print(value); // 输出结果
}).catchError((error) {
    print(error); // 输出错误信息
});

在上面的示例代码中,我们通过 Future.sync 方法创建一个同步执行的 Future 对象,并指定异步操作的执行体为一个返回 'Hello, World!' 的同步函数。然后,我们通过 then 方法输出结果或通过 catchError 方法输出错误信息。

3、Future.value

Future.value 可以创建一个立即完成的 Future 对象,它的值是一个确定的值。这个方法接受一个参数,即要返回的值。

Future.value('Hello, world!').then((value) => print(value)); // 输出 'Hello,world!'

4、Future.error

Future.error 可以创建一个立即完成的 Future 对象,它的值是一个 Error 对象,表示一个错误状态。这个方法接受一个参数,即要抛出的错误对象。

Future.error(Exception('Something wrong happened!'))
.catchError((error) => print(error)); // 输出 'Exception: Something wrong happened!'

5、Future.delayed

Future.delayed 方法用于创建一个延迟一定时间后返回结果的 Future 对象。它接受两个参数,第一个参数 duration 表示延迟的时间,可以是一个 Duration 对象或一个 Duration 对象的毫秒数;第二个参数 compute 表示异步操作的执行体,可以是一个返回结果的异步函数或一个同步函数。示例代码:

Future<String> future = Future.delayed(Duration(seconds: 3), () => 'Hello,World!');
future.then((String value) {
    print(value); // 输出结果
}).catchError((error) {
    print(error); // 输出错误信息
});

在上面的示例代码中,我们通过 Future.delayed 方法创建一个延迟 3 秒后返回结果的 Future 对象,并指定异步操作的执行体为一个返回 'Hello, World!' 的异步函数。然后,我们通过 then 方法输出结果或通过 catchError 方法输出错误信息。

实例方法

1、then方法

then 方法是 Future 类最常用的方法之一,用于处理异步操作的结果。它接受一个回调函数作为参数,当异步操作完成时,会将结果作为参数传递给回调函数,并返回一个新的 Future 对象。

Future<int> fetchNumber() {
    return Future.delayed(Duration(seconds: 1), () => 42);
}

void main() {
    fetchNumber().then((value) => print(value));
}

在上面的示例代码中,fetchNumber 方法返回一个延迟 1 秒的 Future 对象,并在异步操作完成后返回数字 42。在 main 方法中,通过调用 then 方法,将一个回调函数作为参数传递给 Future 对象,当异步操作完成时,将数字 42 作为参数传递给回调函数,并在控制台中打印出来。

1、catchError方法

catchError 方法用于捕获异步操作中的异常。它接受一个回调函数作为参数,当异步操作出现异常时,会将异常作为参数传递给回调函数,并返回一个新的 Future 对象。

Future<int> fetchNumber() {
    return Future.delayed(Duration(seconds: 1), () => throw Exception('Fetch failed'));
}

void main() {
  fetchNumber().catchError((error) => print(error));
}

在上面的示例代码中,fetchNumber 方法返回一个延迟 1 秒的 Future 对象,并在异步操作完成时抛出一个异常。在 main 方法中,通过调用 catchError 方法,将一个回调函数作为参数传递给 Future 对象,当异步操作出现异常时,将异常作为参数传递给回调函数,并在控制台中打印出来。

3、whenComplete方法

whenComplete 方法用于在异步操作完成时执行一些操作,无论异步操作是成功还是失败。它接受一个回调函数作为参数,并返回一个新的 Future 对象,该对象会继承原始的 Future 对象的结果或异常。

Future<int> fetchNumber() {
    return Future.delayed(Duration(seconds: 1), () => 42);
}

void main() {
  fetchNumber().whenComplete(() => print('Fetch complete'));
}

在上面的示例代码中,fetchNumber 方法返回一个延迟 1 秒的 Future 对象,并在异步操作完成后返回数字 42。在 main 方法中,通过调用 whenComplete 方法,将一个回调函数作为参数传递给 Future 对象,当异步操作完成时,无论成功还是失败,都会执行回调函数,并在控制台中打印出一条消息。

4、timeout方法

timeout 方法用于设置异步操作的超时时间。它接受一个 Duration 对象作为参数,并返回一个新的 Future 对象。如果异步操作在指定的时间内未完成,则会抛出一个 TimeoutException 异常。

Future<int> fetchNumber() {
    return Future.delayed(Duration(seconds: 3), () => 42);
}

void main() {
    fetchNumber().timeout(Duration(seconds: 2)).catchError((error) => print(error));
}

在上面的示例代码中,fetchNumber 方法返回一个延迟 3 秒的 Future 对象,并在异步操作完成后返回数字 42。在 main 方法中,通过调用 timeout 方法,将一个 Duration 对象作为参数传递给 Future 对象,指定异步操作的超时时间为 2 秒。如果异步操作在 2 秒内未完成,则会抛出一个 TimeoutException 异常,并在控制台中打印出来。

静态方法

1、Future.any

Future.any 方法用于执行多个异步操作,并返回其中任意一个操作的结果,无论是成功还是失败。它接受一个泛型类型的参数 futures,表示要执行的异步操作列表;返回一个 Future 对象,表示任意一个异步操作的结果。示例代码:

Future<String> action1() {
  return Future.delayed(Duration(seconds: 2), () {
    return 'Action 1';
  });
}

Future<String> action2() {
  return Future.delayed(Duration(seconds: 1), () {
    return 'Action 2';
  });
}

Future<String> action3() {
  return Future.delayed(Duration(seconds: 3), () {
    return 'Action 3';
  });
}

List<Future<String>> futures = [action1(), action2(), action3()];

Future<String> future = Future.any(futures);

future.then((String value) {
  print(value);
}).catchError((error) {
  print(error); // 输出错误信息
});

在上面的示例代码中,我们创建了三个异步操作 action1action2action3,分别模拟了不同的延迟时间,并返回不同的字符串结果。然后,我们将它们放入一个列表 futures 中,并通过 Future.any 方法执行这个列表中的异步操作,返回其中任意一个操作的结果。最后,我们通过 then 方法输出结果。

2、wait方法

wait 方法用于等待多个异步操作完成。它接受一个 Iterable 对象作为参数,并返回一个新的 Future 对象。当所有的异步操作完成时,新的 Future 对象会以一个包含所有结果的列表作为参数传递给 then 方法。

Future<int> fetchNumber(int delaySeconds) {
    return Future.delayed(Duration(seconds: delaySeconds), () => delaySeconds);
}

void main() {
  var futures = [fetchNumber(2), fetchNumber(1), fetchNumber(3)];
  Future.wait(futures).then((values) => print(values));
}

在上面的示例代码中,fetchNumber 方法接受一个参数 delaySeconds,表示延迟的秒数。在 main 方法中,定义一个包含三个异步操作的列表 futures,分别延迟 2、1 和 3 秒,并返回相应的延迟秒数。通过调用 Future.wait 方法,将 futures 列表作为参数传递给 Future 对象,等待所有的异步操作完成。当所有的异步操作完成时,then 方法会以一个包含所有结果的列表作为参数传递给回调函数,并在控制台中打印出来。

总结

以上是 Future 类的常用方法及其使用详解。除此之外,Future 类还有其他一些方法,如 asStreamfirstWherefold 等,可以根据实际需求进行使用。

原文链接:https://juejin.cn/post/7216604684034801701 作者:Nicholas68

(0)
上一篇 2023年4月3日 下午4:42
下一篇 2023年4月3日 下午4:52

相关推荐

发表回复

登录后才能评论