Skip to content

第11章:Dart 异步编程(核心难点,必学)

11.1 同步与异步的区别

同步操作

同步操作是指程序按照代码的顺序执行,前一个操作完成后,才会执行下一个操作。同步操作会阻塞代码的执行,直到操作完成。

异步操作

异步操作是指程序在执行某个操作时,不会等待该操作完成,而是继续执行后续的代码。异步操作不会阻塞代码的执行,而是在操作完成后通过回调或其他方式通知程序。

通俗理解

  • 同步:就像在餐厅点餐,你点完餐后,必须等待服务员把菜端上来,才能继续吃。
  • 异步:就像在餐厅点餐,你点完餐后,可以先做其他事情(比如看手机),等服务员把菜端上来后,再开始吃。

11.2 Dart 异步核心:Future

Future 的定义

Future 是 Dart 中表示异步操作结果的对象。它表示一个可能还没有完成的操作,会在未来的某个时间点完成并返回结果。

Future 的状态

  • 未完成:异步操作正在执行中。
  • 成功:异步操作执行成功,返回结果。
  • 失败:异步操作执行失败,返回错误。

Future 的常用方法

then()

用于处理异步操作成功的情况,接收一个回调函数,该函数的参数是异步操作的结果。

dart
Future<String> fetchData() {
  return Future.delayed(Duration(seconds: 2), () => "Data loaded successfully");
}

void main() {
  fetchData().then((result) {
    print(result); // 输出:Data loaded successfully
  });
}

catchError()

用于处理异步操作失败的情况,接收一个回调函数,该函数的参数是异步操作的错误。

dart
Future<String> fetchData() {
  return Future.delayed(Duration(seconds: 2), () {
    throw Exception("Failed to load data");
  });
}

void main() {
  fetchData()
    .then((result) {
      print(result);
    })
    .catchError((error) {
      print("Error: ${error.toString()}"); // 输出:Error: Exception: Failed to load data
    });
}

whenComplete()

无论异步操作成功还是失败,都会执行的回调函数。

dart
Future<String> fetchData() {
  return Future.delayed(Duration(seconds: 2), () => "Data loaded successfully");
}

void main() {
  fetchData()
    .then((result) {
      print(result);
    })
    .catchError((error) {
      print("Error: ${error.toString()}");
    })
    .whenComplete(() {
      print("Operation completed"); // 无论成功失败都会执行
    });
}

11.3 async/await

async 关键字

async 关键字用于标记一个函数为异步函数。异步函数会返回一个 Future 对象。

await 关键字

await 关键字用于等待一个 Future 对象的完成。它只能在 async 函数中使用。

try-catch

用于捕获异步操作中的错误。

dart
Future<String> fetchData() {
  return Future.delayed(Duration(seconds: 2), () => "Data loaded successfully");
}

Future<void> main() async {
  try {
    var result = await fetchData();
    print(result); // 输出:Data loaded successfully
  } catch (error) {
    print("Error: ${error.toString()}");
  } finally {
    print("Operation completed");
  }
}

11.4 异步遍历

Future.forEach

用于遍历一个集合,并对每个元素执行异步操作。

dart
Future<void> main() async {
  var numbers = [1, 2, 3, 4, 5];
  await Future.forEach(numbers, (number) async {
    await Future.delayed(Duration(seconds: 1));
    print(number);
  });
  print("All numbers processed");
}

await for

用于遍历一个 Stream(流),并对每个元素执行异步操作。

dart
Stream<int> generateNumbers() {
  return Stream.periodic(Duration(seconds: 1), (i) => i).take(5);
}

Future<void> main() async {
  await for (var number in generateNumbers()) {
    print(number);
  }
  print("All numbers received");
}

11.5 实操案例

实现异步请求

dart
import 'dart:io';

Future<String> fetchUrl(String url) async {
  var client = HttpClient();
  try {
    var request = await client.getUrl(Uri.parse(url));
    var response = await request.close();
    return await response.transform(HttpClientResponseDecoder()).join();
  } finally {
    client.close();
  }
}

Future<void> main() async {
  try {
    var content = await fetchUrl("https://example.com");
    print("Fetched content length: ${content.length}");
  } catch (error) {
    print("Error fetching URL: ${error.toString()}");
  }
}

实现延迟执行

dart
Future<void> main() async {
  print("Start");
  await Future.delayed(Duration(seconds: 2));
  print("After 2 seconds");
  await Future.delayed(Duration(seconds: 1));
  print("After another 1 second");
  print("End");
}

11.6 新手易错点

1. await 使用位置错误

await 只能在 async 函数中使用,否则会导致编译错误。

2. 异步代码执行顺序误区

dart
void main() {
  print("1");
  Future.delayed(Duration(seconds: 1), () => print("2"));
  print("3");
}
// 输出:1, 3, 2(而不是 1, 2, 3)

3. 忘记处理异常

在使用 async/await 时,应该使用 try-catch 来捕获可能的异常,否则异常会导致程序崩溃。

4. 不必要的 await

对于不需要等待结果的异步操作,不需要使用 await,否则会阻塞代码的执行。

小结

  • Future 是 Dart 中处理异步操作的核心对象,它表示一个可能还没有完成的操作。
  • async/await 是 Dart 中处理异步操作的语法糖,它让异步代码看起来更像同步代码,提高了代码的可读性。
  • try-catch 用于捕获异步操作中的错误,避免程序崩溃。
  • 异步遍历 可以使用 Future.forEachawait for 来实现。

通过掌握这些异步编程技巧,你可以编写更高效、更响应的 Dart 程序。

© 2026 编程马·菜鸟教程 版权所有