01-Dart异步
Dart的异步模型
- Dart是单线程
1.如何处理耗时操作? 多线程处理:java、c++; 单线程+时间循环:JavaScript、Dart。 2.单线程如何处理耗时操作? 单线程进行异步操作,通过时间循环进行耗时操作。 - dart事件循环
即将需要处理的一系列事件,包括点击事件、IO事件和网络事件等放在一个事件队列中。不断的从事件队列中取出事件,并执行其对应需要执行的代码块,直到事件队列清空位置。
Dart的异步操作
- Future
- 基本使用
1.如何理解? 可以将Future理解成Promise,把耗时的操作放到用Future修饰的函数中,通过.then获取请求的结果,通 过.catchError捕获异常。 2.示例代码: import "dart:io"; main(List<String> args) { var future = getNetworkData(); Future.then((value) { print(value); //输出结果为'hello' }).catchError((err) { print(err); //捕获异常,输出结果为'网络请求出现错误' }); } Future<String> getNetworkData() { return Future<String>(() { sleep(Duration(seconds: 3)); // return "hello"; throw Exception("网络请求出现错误"); // 不再返回结果,而是出现异常 }); } - Future链式调用
import "dart:io"; main(List<String> args) { print("main function start"); getNetworkData().then((value1) { print(value1); return "data2"; }).then((value2) { print(value2); return "data3"; }).then((value3) { print(value3); }); print("main function end"); } Future<String> getNetworkData() { return Future<String>(() { sleep(Duration(seconds: 3)); // 不再返回结果,而是出现异常 return "data1"; }); } //////////////////////////////////// 打印结果如下: main function start main function end // 3s后拿到以下结果 data1 data2 data3 - Future其他API
1.Future.value(val):直接获取一个完成的Future,该Future会直接调用then的回调函数。 Future.value("哈哈哈").then((val) { print(val); //输出 哈哈哈 }); 2.Future.error(object):直接获取一个完成的Future,但是是一个发生异常的Future,该Future会直接调用catchError的回调函数。 Future.error(Exception("错误信息")).catchError((err) { print(err); //输出 Exception: 错误信息 }); 3.Future.delayed(时间, 回调函数):在延迟一定时间时执行回调函数,执行完回调函数后会执行then的回调。 Future.delayed(Duration(seconds: 3), () { return "3秒后的信息"; }).then((value) { print(value); //3秒后输出 3秒后的信息 });
- 基本使用
- await和async
1.即通过同步的代码实现异步的请求。 2.示例: Future<String> getNetworkData() async { var result = await Future.delayed(Duration(seconds: 3), () { return "network data"; }); return "请求到的数据:" + result; } 3.await必须使用在async修饰的函数中; async函数会返回一个Future。
Dart的异步补充
- 任务执行顺序之微任务队列
1.微任务队列的优先级高于事件队列; 2.Flutter开发中,所有的外部事件任务都在事件队列中,如IO、计时器、点击以及绘制事件等;微任务通常来源于Dart内部,并且非常少; 3.Dart单线程中,代码如何执行? 1)dart入口是main函数,即main函数中的代码优先执行; 2)main函数执行完后,会启动一个事件循环,启动后开始执行队列中的任务; 3)按照先进先出的顺序,执行微队列中的所有任务,然后执行事件队列的所有任务。 - 多核cpu的利用
1.Isolate的理解 Dart是单线程的,该线程有自己可以访问的空间以及需要运行的事件循环,将这个空间称之为Isolate,每个Isolate都有自己的事件循环和事件队列,并且他们之间不存在资源共享。但是对于多核cpu来说,如果只有一个Isolate,那么相当于一种资源浪费,故可以自己创建Isolate。 2.创建Isolate main(List<String> args) { Isolate.spawn(foo, "Hello Isolate"); } void foo(info) { print("新的isolate:$info"); } 3.Isolate通信机制(Flutter内部封装了支持Isolate创建和双向通信的函数,仅能用于Flutter项目) main(List<String> args) async { int result = await compute(powerNum, 5); print(result); } int powerNum(int num) { return num * num; } //////////////////////////////////////// 注意:compute里面接受的函数(这里是powerNum)必须是全局的,否则会报错!!!!!!!!!
02-Flutter网络请求
HttpClient类(一般不使用)
是Dart中自带的请求类。
void requestNetwork() async {
// 1.创建HttpClient对象
final httpClient = HttpClient();
// 2.构建请求的url
final url = Url.parse("http://123.207.32.32:8000/api/v1/recommend");
// 3.构建请求
final request = await httpClient.getUrl(url);
// 4.发送请求,必须
final response = await request.close();
if (response.statusCode == HttpStatus.ok) {
print(await response.transform(utf8.decoder).join());
} else {
print(response.statusCode);
}
}
http库(不经常用)
1.是Dart官方提供的请求类,但是没有默认集成到Dart的SDK中,需要在pubspec安装依赖。
2.示例:
import'package:http/http.dart'as http;
void httpNetwork() async {
// 1.创建Client
final client = http.Client();
// 2.构建url
final url = Url.parse("http://123.207.32.32:8000/api/v1/recommend");
// 3.发送请求
final response = await client.get(url);
// 4.获取结果
if (response.statusCode == HttpStatus.ok) {
print(response.body);
} else {
print(response.statusCode);
}
}
dio三方库(经常使用)
1.是Dart的请求库,支持Restful API、FormData、拦截器、请求取消、cookie管理、文件上传/下载、超时、自定义适配等。
2.使用:
先在pubspec中写入依赖;
dio:^3.0.1
封装dio库。
1)配置基本信息:http_config.dart
class HTTPConfig {
static const baseURL = "https://httpbin.org";
static const timeout = 5000;
}
2)封装请求:http_request.dart
import'package:dio/dio.dart';
// import'package:testflutter001/service/config.dart';
class HttpRequest {
// 配置参数:路径、请求时间、contentType、headers等
static final BaseOptions options = BaseOptions(
baseUrl: HTTPConfig.baseURL,
connectTimeout: HTTPConfig.timeout
);
static final Dio dio = Dio(options); //创建一个Dio实例并且配置,该配置是公共配置
static Future<T> request<T>(String url,{
String method = 'get',
Map<String, dynamic> params,
Interceptor inter
}) async {
// 1.每个请求还可以单出配置,该单独配置可以覆盖公共配置中的信息
final options = Options(method: method);
// 全局拦截器
// 创建默认的全局拦截器
Interceptor dInter = InterceptorsWrapper(
onRequest: (options) {
// 在进行任何网络请求的时候, 可以添加一个loading显示
// 很多页面的访问必须要求携带Token,那么就可以在这里判断是有Token
// 对参数进行一些处理,比如序列化处理等
print("拦截了请求");
return options;
},
onResponse: (response) {
print("拦截了响应");
return response;
},
onError: (error) {
print("拦截了错误");
return error;
}
);
List<Interceptor> inters = [dInter];
//请求单独拦截器
if (inter != null) {
inters.add(inter);
}
//统一添加到拦截器中
dio.interceptors.addAll(inters);
// 2.发送网络请求
try {
Response response = await dio.request<T>(url, queryParameters: params, options: options);
return response.data;
} on DioError catch(e) {
return Future.error(e);
}
}
// static void get() {
// request(url, method: get);
// }
}
3)具体使用:
HttpRequest.request("https://httpbin.org/get", params: {"name": "why", 'age': 18},inter:InterceptorsWrapper(onRequest:(){},onResponse:(){},onError:(){},).then((res) {
print(res);
});
HttpRequest.request("https://httpbin.org/post",method: "post", params: {"name": "why", 'age': 18}).then((res) {
print(res);
});