变量声明
var
类似于 JavaScript 中的 var
,它可以定义变量
最大的不同是 Dart 中 var
变量一旦赋值,类型便会确定,不能改变其类型
dynamic
和 Object
Object
是 Dart 所有对象的根基类,也就是说所有类型都是 Object
的子类(包含 Function 和 NULL),所以任何类型的数据都可以赋值给 Object
声明的对象,dynamic
与 var
一样都是关键词,声明的变量可以赋值任意对象。
相同之处
dynamic
与 Object
声明的变量可以在后期改变赋值类型
不同之处
dynamic
声明的对象编译器会提供所有可能的组合,而 Object
声明的对象只能使用 Object
的属性和方法,否则编译器会报错
final
和 const
如果你从未打算更改一个变量,那么使用 final
或 const
,不是 var
,也不是一个类型。一个 final
变量只能被设置一次。被 final
或者 const
修饰的变量,变量类型可以省略
不同之处
const
变量是一个编译时常量,final
变量在第一次使用时被初始化
函数
Dart 是一种真正的面向对象的语言,所以即使是函数也是对象,并且有一个类型 Function。这意味着函数可以赋值给变量或作为参数传递给其他函数,这是函数式编程的典型特征
函数声明
Dart 函数声明如果没有显式声明返回值类型时会默认当做 dynamic
处理,注意,函数返回值没有类型推断
可选的位置参数
包装一组函数参数,用[]
标记为可选的位置参数
可选的命名参数
定义函数时,使用{param1, param2,...}
,用于指定命名参数
调用函数时,可以传参。如果传参,就必须使用指定形参的名称。例如:paramName: value
异步支持
Dart 类库有非常多的返回 Future
或者 Stream
对象的函数。这些函数被称为 异步函数 :它们只会在设置好一些耗时操作之后返回,比如像IO操作。而不是等到这个操作完成
async
和 await
关键词支持了异步编程,允许我们写出和同步代码很像的异步代码
Future
Future
与 JavaScript 中的 Promise
非常相似,表示一个异步操作的最终完成(或失败)及其结果值的表示。简单来说,它就是用于处理异步操作的,异步处理成功了就执行成功的操作,异步操作失败了就捕获错误或者停止后续操作。一个 Future
只会对应一个结果,要么成功,要么失败
Future
的所有 API 的返回值仍然是一个 Future
对象,所以可以很方便的进行链式调用
Future.then
Future.delayed(new Duration(seconds: 2), (){
return "hi.world";
}).then((data){
print(data);
})
Future.catchError
如果异步任务发生错误,我们可以在 catchError
中捕获错误
Future.delayed(new Duration(seconds: 2), (){
return "hi.world";
}).then((data){
print(data);
}).catchError((e){
// 执行失败会走到这里
print(e);
})
不是只有 catchError
回调才能捕获错误,then
方法还有一个可选参数 onError
,我们也可以用它来捕获异常
Future.delayed(new Duration(seconds: 2), (){
return "hi.world";
}).then((data){
print(data);
}, onError: (e){
print(e);
});
Future.whenComplete
有些时候,我们会遇到无论异步任务执行成功或失败都需要做一些事的场景,比如在网络请求前弹出加载对话框,在请求结束后关闭对话框。
这种场景,有两种方法,第一种是分别在 then
或 catch
中关闭一下对话框,第二种就是使用 Future
的 whenComplete
回调
Future.delayed(new Duration(seconds: 2), (){
return "hi.world";
}).then((data){
// 执行成功会走到这里
print(data);
}, onError: (e){
// 执行失败会走到这里
print(e);
}).whenComplete((){
// 无论成功或失败都会走到这里
});
Future.wait
它接收一个 Future
数组参数,只有数组中所有 Future
都执行成功后,才会触发 then
的成功回调,只要有一个 Future
执行失败,就会触发错误回调。
Future.wait([
// 2秒后返回结果
Future.delayed(new Duration(seconds: 2), (){
return 'hello';
}),
// 4秒后返回结果
Future.delayed(new Duration(seconds:4), (){
return ' world';
})
]).then((results){
print(result[0]+result[1]);
}).catchError((e){
print(e);
})
Async/await
回调地狱(Callback Hell)
如果代码中有大量的异步逻辑,并且出现大量异步任务依赖其它异步任务的结果时,必然会出现 Future.then
回调中套回调情况
可以感受一下,如果业务逻辑中由大量异步依赖的情况,将会出现在回调里面套回调的情况,过多的嵌套会导致代码可读性下降以及出错率提高,并且非常难维护,这个问题被形象的称为回调地狱(Callback Hell)
使用 async/await
消除 callback hell
Future<String> login(String userName, String pwd){
// 用户登录
}
Future<String> getUserInfo(String id){
// 获取用户信息
}
Future saveUserInfo(String userInfo){
// 保存用户信息
}
task() async{
try{
String id = await login('alice', '*****');
String userInfo = await getUserInfo(id);
await saveUserInfo(userInfo);
}catch(e){
// 错误处理
print(e);
}
}
async
用来表示函数是异步的,定义的函数会返回一个Future
对象,可以使用 then 方法添加回调函数await
后面是一个Future
,表示等待该异步任务完成,异步完成后才会往下走;await
必须出现在async
函数内部其实,无论是在 JavaScript 还是 Dart 中,
async/await
都只是一个语法糖,编译器或解释器最终都会将其转化为一个 Promise(Future) 的调用链
Stream
Stream
也是用于接收异步事件数据,和 Future
不同的是,它可以接收多个异步操作的结果(成功或失败)。也就是说,在执行异步任务时,可以通过多次触发成功或失败事件来传递结果数据或错误异常。Stream
常用于会多次读取数据的异步任务场景,如网络内容下载、文件读写等
Stream.fromFutures([
// 1秒后返回结果
Future.delayed(new Duration(seconds: 1), (){
return 'hello 1';
}),
// 抛出一个异常
Future.delayed(new Duration(seconds: 2), (){
throw AssertionError('Error');
}),
// 3秒后返回结果
Future.delayed(new Duration(seconds: 3), (){
return 'hello 3';
})
]).listen((data){
print(data);
}, onError: (e){
print(e.message);
}, onDone: (){
});
上面的代码依次会输出
I/flutter (17666): hello 1
I/flutter (17666): Error
I/flutter (17666): hello 3