Dart代码在单线程中执行
代码在运行线程中阻塞的话,会使程序冻结
Future对象(futures)表示异步操作的结果,进程或者IO会延迟完成
在async函数中使用await来挂起执行,直到future完成为止(或者使用then)
在async函数中使用try-catch来捕获异常(或者使用catchError())
Future.delayed()
=>延迟执行一个延时任务。
Future.then()=>
任务执行完成会进入这里,能够获得返回的执行结果。
Future.delayed(Duration(seconds: 2), () {
return 'hello world';
}).then((value) => print(value));//输出:hello world
Future.catchError()
=>有任务执行失败,可以在这里捕获异常。
Future.delayed(Duration(seconds: 2), () {
return (3 ~/ 0);
}).catchError((e) {
print("异常信息:${e.toString()}");
}).then((value) => print(value));
//输出结果:异常信息:IntegerDivisionByZeroException
Future.whenComplete()
=>当任务停止时,最后会执行这里。
Future.delayed(Duration(seconds: 2), () {
return "hello world";
}).then((value) => print(value)).whenComplete(() => print("任务已结束"));
输出打印:
hello world
任务已结束
Future.wait()=>
可以等待多个异步任务执行完成后,再调用 then()
。Future.wait([])接受一个Future数组参数。含义为当数组中的所有的Future都处理完成后,再对每个Future的结果进行处理。
其结果同样返回一个Future数组。可以通过数组下标访问。
Future.wait([
//2s后返回
Future.delayed(Duration(seconds: 2), () {
return 'Hello';
}),
//4s后返回
Future.delayed(Duration(seconds: 4), () {
return ' world';
})
]).then((value) {
print(value[0] + value[1]);//输出打印:Hello world
print(value[0]);//输出打印:Hello
});
catchError()
。 Future.wait([
//2s后返回
Future.delayed(Duration(seconds: 2), () {
return 'Hello';
}),
//4s后返回
Future.delayed(Duration(seconds: 4), () {
throw '完了,芭比Q了';
})
]).then((value) {
print(value[0] + value[1]);
}).catchError((e) {
print("异常信息:${e}");
});
//异常信息:完了,芭比Q了
程序往下走到catchError后面的的方法,输出异常信息,而没有走到then,因为只有程序正常执行才会走到then。注意then 要写在catchError后面。
其实不止catchError方法可以捕获异常,在then方法中还提供了一个可选参数onError,当发生异常的时候,会走到onError参数所传入的方法
Future.wait([
//2s后返回
Future.delayed(Duration(seconds: 2), () {
return 'Hello';
}),
//4s后返回
Future.delayed(Duration(seconds: 4), () {
throw '完了,芭比Q了';
})
]).then((value) {
print(value[0] + value[1]);
},onError: (e){
print("then中的onError异常信息:${e.toString()}");
});
输出打印:hen中的onError异常信息:完了,芭比Q了
若同时设置then方法的onError参数和调用catchError方法,
Future.wait([
//2s后返回
Future.delayed(Duration(seconds: 2), () {
return 'Hello';
}),
//4s后返回
Future.delayed(Duration(seconds: 4), () {
throw '完了,芭比Q了';
})
]).then((value) {
print(value[0] + value[1]);
},onError: (e){
print("then中的onError异常信息:${e.toString()}");
}).catchError((e) {
print("catchError 异常信息:${e}");
});
输出结果:then中的onError异常信息:完了,芭比Q了
结果:可以看到当同时设置onError和catchError的时候,当发生异常时,程序只会走onError,而不会走到catchError
必须在带有 async 关键字的 异步函数 中使用 await
:
比如现在有个需求场景是用户先登录,登录成功后会获得用户ID,然后通过用户ID,再去请求用户个人信息,获取到用户个人信息后打印
//用户登录
Future login(String userName, String pwd) async {
if (userName == "jack" && pwd == "123456") {
return "token";
}
return "false";
}
Future getUserInfo(String id) async {
//获取用户信息
return "usrName=jack,age=18,id=$id";
}
Future saveUserInfo(String userInfo) async {
// 保存用户信息,打印
print("userInfo:$userInfo");
回调地狱的做法:
login("jack", "123456").then((id) => {
getUserInfo(id).then((userInfo) => {
saveUserInfo(userInfo)
})
});
上面定义的每一个方法都是异步的,都是返回一个Future,所以还有一种比较优雅的实现方法,就是用Future.then的链式调用,在上一个任务的回调里返回下一个任务的执行结果,也就是返回一个Future,而这个任务的回调可以通过Future.then链式调用的方式拼在上一个then的后面,这就避免了多层的回调,执行代码如下所示
login("jack", "123456").then((id) {
return getUserInfo(id);
}).then((userInfo) {
return saveUserInfo(userInfo);
}).catchError((e) {
print(e);
});
使用async/await消除callback hell
通过Future回调中再返回Future的方式虽然能避免层层嵌套,但是还是有一层回调.
使用async/await消除这种嵌套:
async 位于函数名称后面,函数体前,await用在函数体内,其他方法调用前。
void getUser() async {
try {
var id = await login("jack", "123456");
var userInfo = await getUserInfo(id);
await saveUserInfo(userInfo);
} catch (e) {
print(e);
}
}
通过async/await将一个异步流用同步的代码表示出来了。