目录导航
Dart是单线程执行模式(
single-threaded execution model),
Isoalte是对线程的上层封装,代表一个执行环境。不同执行环境(Isolate)之间内存不共享。 Dart的异步操作不一定在另一个线程(
Isolate)中执行,而且通常是在同一个线程(
Isolate)中执行。
事件循环与事件队列
每个Isoalte都包含一个事件循环器(event loop)和与之关联的两个队列——事件队列(event queue)和微任务队列(microtask queue)。当Main Isolate的Main方法执行完毕后,event loop开始依次从与之关联的队列里取出事件执行。这与Android中的Handler机制非常类似,但与之不同的是,Isolate除了event queue外,还有一个microtask queue,microtask queue的优先级高于event queue,event loop总是优先处理microtask queue里的事件。流程图如下:

如上图所示,event loop会首先判断microtask queue是否为空。若不为空,依次取出mcrotask queue中的事件处理,直至它为空;若为空,则尝试从event queue中取出一个事件处理,处理完毕会再次判断microtask queue的情况,不为空的话则优先处理microtask queue,直至它为空。也就是说,每执行完event queue中的一个事件,event loop都要判断下microtask queue的情况以优先处理它。microtask queue的存在,使得事件处理可以存在“插队行为”。
future vs await
future
执行异步代码
我们通过Future对象执行异步代码,Future提供了多种方式传入异步代码,构造器传入是其中一种:
Future asyncMethod() {
return Future(() {
//异步代码
});
}
异步方法会同步返回Future对象作为异步代码的执行结果的代言人,供调用方使用。
- 没有结果值的异步代码
Future printHelloWorld() {
return Future(() => print("Hello,world!"));
}
- 有结果值的异步代码
Future<int> provideOneInt() {
return Future(() => 1);
}
处理异步代码的结果
then
then方法需传入一个结果处理函数,当异步代码执行完毕后,会执行该函数处理结果。结果处理函数携带一个形参,代表结果值。只有异步代码成功执行(没有抛出异常),then方法传入的结果处理函数才会被调用。
- 无结果值的异步方法
printHelloWorld().then((value) => print("print hello world complete!$value"));
由于printHelloWorld没有结果值,所以value的值为null。你可以直接用_代替value:
printHelloWorld().then((_) => print("print hello world complete!"));
- 有结果值的异步方法
provideOneInt().then((value) => print("I received a int:$value"));
then方法的返回值为Future类型。当传入的函数返回Future类型时,then直接返回该future;当为其他类型值时,then返回一个包裹该值Future对象。
catchError
catchError用于处理抛出的异常:
provideOneInt()
.then((value) => print("I received a int:$value"))
.catchError((ex) {
//handle the error
});
catchError的返回值为Future类型。当捕获到异常时,返回的Future是异常处理函数返回的Future或包裹异常处理函数返回值的Future;当未捕获到异常时,catchError原样传递Future。
所以,catchError的调用位置很重要。当在then方法后调用catchError,会捕获异步代码和结果处理代码抛出的异常。如果直接在原始Future上调用catchError,只会捕获异步代码抛出的异常,如:
provideOneInt().catchError((ex) {
//handle the error
}).then((value) => print("I received a int:$value"));
在上面的代码中,catchError只能捕获provideOneInt抛出的异常。而且当抛出异常时,then处理的是错误处理函数的结果,而不是provideOneInt返回的结果。如果没有抛出异常,由于cachError只会原样传递,所以处理的是t
provideOneInt的结果。
whenComplete
then方法传入的结果处理函数只在异步代码成功执行的情况下调用,catchError方法传入的错误处理函数只在代码抛出异常的时候调用。whenComplete传入的处理函数,不管是否抛出异常都会执行。相当于finally。
provideOneInt()
.then((value) => print("I received a int:$value"))
.catchError((ex) {
//handle the error
}).whenComplete(() {
//finally code
});
多个异步方法的链式调用
await 关键字
当调用返回值为Future的异步方法时,如果不想使用Future提供的callback式的api,可以使用await关键字。
await关键字会导致当前方法等待,直至异步方法返回结果,当前方法才继续向下执行。
使用await关键字的前提是当前方法用async修饰。被async关键字修饰,且内部含有await表达式的方法本身是异步的,在方法内部,await 调用的异步方法会同步返回结果。
void printInt() async {
int value = await provideOneInt();
print("print the int:$value");
}
异常处理
void printInt() async {
try {
int value = await provideOneInt();
print("print the int:$value");
} catch (ex) {
//handle the error
} finally {
//finally code
}
}
stream vs await for
Stream<int> streamIntValues() {
return Stream<int>.fromIterable([1, 2, 3, 4, 5]);
}
void callbackMode() {
streamIntValues()
.listen((value) => print(value), onDone: () => print("on done."));
}
void awaitForMode() async {
await for (int value in streamIntValues()) {
print(value);
}
}

本文深入探讨了Dart语言中的异步编程概念和技术,包括事件循环与事件队列的工作原理,Future与await关键字的区别及使用场景,以及如何处理异步代码的结果。此外,还介绍了Stream与Isolate在异步编程中的作用。
1800

被折叠的 条评论
为什么被折叠?



