变量声明
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