Dart是单线程的,不支持多线程。
Dart实现异步是使用的单线程+循环调用的方式
类似于网络请求、文件读写的IO操作,都可以基于非阻塞调用
阻塞和非阻塞关注的是程序在等待调用结果(消息、返回值)时的状态
阻塞式调用: 调用结果返回之前,当前线程会被挂起,调用线程只有在得到调用结果之后才会继续执行
非阻塞式调用: 调用执行后,当前线程不会停止执行,只需要过一段时间来检查一下有没有结果返回即可
单线程模型中主要就是在维护着一个事件循环(Event Loop)
事件循环是什么:
1.将需要处理的一系列事件(包括点击事件、IO事件、网络事件)放在一个事件队列(Event Queue)中。
2.不断的从时间队列(Event Queue)中取出事件,并执行其对应需要执行的代码块,直到时间队列清空位置
Dart中的异步操作主要使用Future以及async、await
import 'dart:io';
main(List<String> args) {
print("main start");
//发送一个网络请求
var result = getNetworkData();
print(result);
print("main end");
}
//模拟一个网络请求
String getNetworkData(){
sleep(Duration(seconds:2));
return "Hello World";
}
输出结果
main start
//控制台输出在此处有等待
Hello World
main end
此时网路请求阻塞了线程
加入Future后
import 'dart:io';
main(List<String> args) {
print("main start");
//发送一个网络请求
var future = getNetworkData();
print(future);
//2.拿到结果
//then后面的回调函数什么时候被执行?
//需要在Future(函数)有结果,才执行下面的回调函数
future.then((value){
print(value);
}).catchError((err){
print("打出错误:$err");
}).whenComplete(() => {
print("代码执行完成")
});
print("main end");
}
//模拟一个网络请求
Future getNetworkData(){
return Future((){
//1.将耗时操作包裹到Future的回调函数中
//1.1结果情况1:只要有返回结果,就执行Future对应的then的回调
//1.2结果情况2:如果没有结果返回(有错误信息),需要在Future回调中抛出一个异常
sleep(Duration(seconds:2));
//模拟结果情况1
return "Hello World";
//模拟结果情况2
throw Exception("我是错误信息");
});
}
main start
Instance of 'Future<dynamic>'
main end
Hello World
代码执行完成
main start
Instance of 'Future<dynamic>'
main end
打出错误:Exception: 我是错误信息
代码执行完成
import 'dart:io';
main(List<String> args) {
print("main start");
Future((){
//1.发送第一次请求
sleep(Duration(seconds:8));
return "第一次的结果";
}).then((value){
print(value);
//2.发送的第二次请求
sleep(Duration(seconds:3));
//return "第二次的结果";
throw Exception("第二次请求异常");
}).then((value){
print(value);
}).catchError((err){
print(err);
}).whenComplete(() => {
print("代码完成")
});
print("main end");
}
await、async是Dart中的关键字,他们可以让我们用同步的代码格式,去实现异步的调用过程。并且,通常一个async的函数会返回一个Future。
不使用异步时
main(List<String> args) {
print("main start");
var result = getNetworkData();
print(result);
print("main end");
}
String getNetworkData(){
sleep(Duration(seconds:3));
return "Hello World";
}
main start
//程序在这里阻塞,3秒后打印出后面内容
Hello World
main end
使用Future时
main(List<String> args) {
print("main start");
var result = getNetworkData().then((value) {
print(value);
});
print(result);
print("main end");
}
Future getNetworkData(){
return Future((){
sleep(Duration(seconds:5));
return "使用了Future";
});
}
main start
Instance of 'Future<Null>'
main end
//程序在这里等待5秒后输出结果,不阻塞main end
使用了Future
使用await、async
await、async相当于Future的语法糖
1.await必须在async函数中才能使用
2.async函数返回的结果必须是一个Future
await需要写在耗时操作之前,表示等待该操作结果
main(List<String> args) {
print("main start");
var result = getNetworkData().then((value) {
print(value);
});
print(result);
print("main end");
}
Future getNetworkData() async {
var response = await (这里写耗时操作);
return "Hello World";
}
虽然return写的返回String,内部会自动包裹为Future
main start
Instance of 'Future<Null>'
main end
Hello World
例
链式调用普通写法
main(List<String> args) {
print("main start");
getData();
print("main end");
}
void getData(){
//1.调用第一次网络请求
getNetworkData("argument1").then((value){
print(value);
return getNetworkData(value);
}).then((value) {
print(value);
return getNetworkData(value);
}).then((value) {
print(value);
});
}
Future getNetworkData(String arg){
return Future((){
sleep(Duration(seconds:3));
return "Hello World "+arg;
});
}
main start
main end
Hello World argument1
Hello World Hello World argument1
Hello World Hello World Hello World argument1
使用await、async进行链式调用
main(List<String> args) {
print("main start");
getData().then((value){
print("最终结果$value");
}).catchError((err){
print(err);
});
print("main end");
}
Future getData() async{
//1.调用第一次网络请求
var res1 = await getNetworkData("argument1");
print(res1);
var res2 = await getNetworkData(res1);
print(res2);
var res3 = await getNetworkData(res2);
print(res3);
return res3;
}
Future getNetworkData(String arg){
return Future((){
sleep(Duration(seconds:3));
return "Hello World "+arg;
});
}
//第一个参数是方法的名称
//第二个参数是给方法传的参数
import "dart:isolate";
main(List<String> args) {
Isolate.spawn(foo, "Hello Isolate");
}
void foo(info) {
print("新的isolate:$info");
}
新的isolate:Hello Isolate
但是在真实开发中,我们不会只是简单的开启一个新的Isolate,而不关心它的运行结果:
import "dart:isolate";
main(List<String> args) async {
// 1.创建管道
ReceivePort receivePort= ReceivePort();
// 2.创建新的Isolate
Isolate isolate = await Isolate.spawn<SendPort>(foo, receivePort.sendPort);
// 3.监听管道消息
receivePort.listen((data) {
print('Data:$data');
// 不再使用时,我们会关闭管道
receivePort.close();
// 需要将isolate杀死
isolate?.kill(priority: Isolate.immediate);
});
}
void foo(SendPort sendPort) {
sendPort.send("Hello World");
}
但是我们上面的通信变成了单向通信,如果需要双向通信呢?
main(List<String> args) async {
int result = await compute(powerNum, 5);
print(result);
}
int powerNum(int num) {
return num * num;
}
在Flutter中常见的网络请求方式有三种:HttpClient、http库、dio库
HttpClient是dart自带的请求类,在io包中,实现了基本的网络请求相关的操作。
网络调用通常遵循如下课步骤:
void requestNetwork() async{
//1.创建HttpClient对象
final httpClient = HttpClient();
//2.构建请求的uri
final uri = Uri.parse("https://wanandroid.com/wxarticle/chapters/json");
//3.构建请求
final request = await httpClient.getUrl(uri);
//4.发送请求,必须
final response = await request.close();
if(response.statusCode == HttpStatus.ok){
print(await response.transform(utf8.decoder).join());
}else{
print(response.statusCode);
}
}
http是Dart官方提供的另一个网络请求类,相比于HttpClient,易用性提升了。但是,没有默认集成到Dart的SDK中,所以我们需要先在pubspec.yaml中依赖它
http:^0.12.0+2
import 'package:http/http.dart' as http;
void requestNetwork() async{
//1.创建Client
final client = http.Client();
//2.构建uri
final url = Uri.parse("https://wanandroid.com/wxarticle/chapters/json");
//3.发送请求
final response = await client.get(url);
//4.获取结果
if(response.statusCode == HttpStatus.ok) {
print(response.body);
}else{
print(response.statusCode);
}
}
dio是一个强大的Dart Http请求库,支持Restful API、FormData、拦截器、请求取消、Cookie管理、文件上传/下载、超时、自定义适配等
dio: ^3.0.10