说明
在很多语法中,回调处理异步任务是很常见的操作,然而回调多了是一件很老火的事情。Dart给了我们很友好的方式,可以允许我们写出和同步代码很像的异步代码。
1,Future
Future一个异步操作的最终完成(或失败)及其结果值的表示。简单来说,它就是用于处理异步操作的,异步处理成功了就执行成功的操作,异步处理失败了就捕获错误或者停止后续操作。一个Future只会对应一个结果,要么成功,要么失败。Future 的所有API的返回值仍然是一个Future对象,所以可以很方便的进行链式调用。
1.1 Future一些常用的方法
Future.then:接收异步结果;
Future.catchError:如果异步任务发生错误,我们可以在catchError中捕获错误;
Future.whenComplete:无论成功或失败都会走到这里;
Future.wait:需要等待多个异步任务都执行结束后才进行一些操作;
Future.delayed(Duration(seconds: 2),(){
//return "hi world!";
throw AssertionError("Error");
}).then((data){
//执行成功会走到这里
print(data);
}).catchError((e){
//执行失败会走到这里
print(e);
}).whenComplete((){
//无论成功或失败都会走到这里
});
Future.wait([
// 2秒后返回结果
Future.delayed(Duration(seconds: 2), () {
return "hello";
}),
// 4秒后返回结果
Future.delayed(Duration(seconds: 4), () {
return " world";
})
]).then((results){
print(results[0]+results[1]);
}).catchError((e){
print(e);
});
2,async/await
async/await提供一种语法糖,使异步任务串行化,更有利于理解可读。
2.1 回调地狱(Callback Hell)
如果代码中有大量异步逻辑,并且出现大量异步任务依赖其他异步任务的结果时,必然会出现Future.then回调中套回调情况。过多的嵌套会导致的代码可读性下降以及出错率提高,并且非常难维护,这个问题被形象的称为回调地狱(Callback Hell)。如下示例:
login("alice","******").then((id){
//登录成功后通过,id获取用户信息
getUserInfo(id).then((userInfo){
//获取用户信息后保存
saveUserInfo(userInfo).then((){
//保存用户信息,接下来执行其他操作
...
});
});
})
2.2 消除回调地狱
消除回调地狱,有2种方法:
- 1,使用Future消除Callback Hell:Future 的所有API的返回值仍然是一个Future对象,所以可以很方便的进行链式调用” ,如果在then 中返回的是一个Future的话,该future会执行,执行结束后会触发后面的then回调,这样依次向下,就避免了层层嵌套;
- 2,使用 async/await 消除 callback hell:async用来表示函数是异步的,定义的函数会返回一个Future对象,可以使用 then 方法添加回调函数。await 后面是一个Future,表示等待该异步任务完成,异步完成后才会往下走;await必须出现在 async 函数内部。
//使用Future消除Callback Hell
login("alice","******").then((id){
return getUserInfo(id);
}).then((userInfo){
return saveUserInfo(userInfo);
}).then((e){
//执行接下来的操作
}).catchError((e){
//错误处理
print(e);
});
//使用 async/await 消除 callback hell
task() async {
try{
String id = await login("alice","******");
String userInfo = await getUserInfo(id);
await saveUserInfo(userInfo);
//执行接下来的操作
} catch(e){
//错误处理
print(e);
}
}
其实,async/await 只是一个语法糖,编译器或解释器最终都会将其转化为一个Future的调用链。