Appearance
第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.forEach或await for来实现。
通过掌握这些异步编程技巧,你可以编写更高效、更响应的 Dart 程序。
