并发
在应用中,所有的 Dart 代码都在 isolate 中运行。
每一个 Dart 的 isolate 都有独立的运行线程, 无法和其他线程共享对象, 只能用消息机制通信, dart应用默认使用一个isolate, 开发者可以创建多个isolate
dart是单线程+事件循环
1、当用户点击时,onPressed回调函数被放入事件循环中执行,执行的过程中发送了一个网络请求。
2、网络请求发出去后,该事件循环不会被阻塞,而是发现要执行的onPressed函数已经结束,会将它丢弃掉。
3、网络请求成功后,会执行then中传入的回调函数,这也是一个事件,该事件被放入到事件循环中执行,执行完毕后,事件循环将其丢弃。
作者:coderwhy
异步类和语法
Dart类库有非常多的返回Future或者Stream对象的异步函数
异步函数 : 调用方不会等到此函数操作完成后才返回, 调用方会获得一个future对象, 然后对其调用then()传入一个函数, 当future有结果时, 此函数被回调 (实际上是future有结果时将回调函数放到事件循环中)
一个最终会返回 int 类型值的 promise,应当声明为 Future
一个会持续返回一系列 int 类型值的 promise,应当声明为 Stream
Future类
factory Future(FutureOr<T> computation()) {}
当调用此工厂构造方法时, 传入的函数就会被一个_Future对象异步执行(类似java中将callble对象最为参数传入线程池的submit() )
factory Future(FutureOr<T> computation()) {
_Future<T> result = new _Future<T>();
Timer.run(() {
try {
result._complete(computation());
} catch (e, s) {
_completeWithErrorCallback(result, e, s);
}
});
return result;
}
// -------- Future()中传入的函数默认是异步执行的, 示例如下
// 输出 :
// main start
// main end
// after sleep 3 s
void main() {
print('main start');
// 调用异步函数, 获得future对象
var future = asyncFunc();
// 调用then, 传入回调函数,
future.then((s){
print(s);
});
print('main end');
}
// 异步函数中返回future对象, 其中传入一个执行函数, 此函数返回FutureOr<T>对象
Future<String> asyncFunc(){
return Future((){
sleep(Duration(seconds: 3));
return "after sleep 3 s";
});
}
// -------- 可以用Future()控制代码执行顺序
void main() async {
print('----main start');
// 下面两行代码运行结果一样, 异步执行funA()然后异步执行funB()
Future(funA).then((value) => funB());
Future(funA).then((value) => Future(() => funB()));
// 此时会等待funA()执行完后等待funB()执行
await Future(funA);
await Future(funB);
// 由于dart默认在一个isolate中运行, 这样并不会加快运行时长, 仍是2s
Future(funA);
Future(funB);
print('----main end');
}
void funA() {
print("funA start...");
sleep(Duration(seconds: 1));
print("funA end...");
}
void funB() {
print("funB start...");
sleep(Duration(seconds: 1));
print("funB end...");
}
async+await
使用async+await可以在调用异步函数时实现调用同步函数的效果
也就是主线程等待await修饰的异步函数返回后再执行下面的代码
await
代表等待future对象的结果, 加了await的函数会等待future运行结束并自动将返回值拆出来
加在Future对象或返回Future对象的函数前
只能在在async修饰的函数中使用await
/*
此代码的输出:
main start
asyncFunc : 3
asyncFunc : 2
asyncFunc : 1
ret type = String
main : 3
main : 2
main : 1
main end
*/
void main() async {
print('main start');
//当调用asyncFunc()前面的await去掉时, ret的type是future<String> , 有await时, ret type=String
var ret = await asyncFunc();
print('ret type = ${ret.runtimeType}');
sleepThreeSecond("main");
print('main end');
}
Future<String> asyncFunc() async {
sleepThreeSecond("asyncFunc");
return "async func end";
}
void sleepThreeSecond(String tag) {
var i = 3;
while (i > 0) {
sleep(Duration(seconds: 1));
print('$tag : $i');
i--;
}
}
async
修饰的函数的返回值会自动被Future包裹, 注意并不是整个函数被Future()包裹
所以下面代码中ret的类型是Future<String>
void main() async{
var ret = asyncFunc();
print('$ret'); //output : Instance of 'Future<String>'
}
Future<String> asyncFunc()async{
return "async func end";
}
错误处理
异步函数如果出现异常, 在then()后调用.catchError()传入异常回调函数来捕获
main(List<String> args) {
print("main function start");
var future = getNetworkData();
future.then((value) {
print(value);
}).catchError((error) { // 捕获出现异常时的情况
print(error);
});
print(future);
print("main function end");
}