共计 4104 个字符,预计需要花费 11 分钟才能阅读完成。
事件循环、Isolate
开始前咱们须要明确 Dart 是单线程的并且 Flutter 依赖于 Dart
如果你晓得 js 中的 event loop 将很好了解 dart 的整个异步过程
先看一段代码
import 'dart:async';
Future eventLoop() async{print('A');
Future((){print('F');
scheduleMicrotask((){print('H');});
Future((){print('M');
}).then((_){print('N');
});
}).then((_){print('G');
});
Future((){print('I');
}).then((_){print('J');
});
scheduleMicrotask(text1);
scheduleMicrotask((){print('D');});
print('B');
}
void text1() {print('C');
scheduleMicrotask((){print('E');});
Future((){print('K');
}).then((_){print('L');
});
}
你只到输入后果吗
正确的输入程序是: A B C D E F G H I J K L M N
eventLoop
1、MicroTask 队列
微工作队列,个别应用 scheduleMicroTask
办法向队列中增加
这是大多数时候你不用应用的货色。比方,在整个 Flutter 源代码中 scheduleMicroTask() 办法仅被援用了 7 次,所以最好优先思考应用 Event 队列
2、Event 队列
I/O、手势、绘图、计时器、流、futures 等等
异步操作都将进入 event 队列
尽量应用事件队列能够使微工作队列更短,升高事件队列卡死的可能性
代码执行程序
首先咱们晓得 dart 是单线程的,所以 dart 的代码执行程序是:
- 同步代码顺次执行
- 碰到异步代码先进对应的队列中,而后继续执行上面的代码
- 当同步代码执行结束,先去看 MicroTask 队列中的工作,将 MicroTask 队列中的工作顺次执行结束
- MicroTask 中的工作执行结束后,再去看 Event 队列中的工作,event 队列出一个工作 而后执行,而后回到第三步 循环 直到所有队列都清空
Isolate
Isolate 是 Dart 中的 线程,Flutter 的代码都是默认跑在 root isolate 上的
「Isolate」在 Flutter 中并不共享内存。不同「Isolate」之间通过「音讯」进行通信。
import 'dart:async';
import 'dart:io';
import 'dart:isolate';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
// 一个普普通通的 Flutter 利用的入口
//main 函数这里有 async 关键字,是因为创立的 isolate 是异步的
void main() async{runApp(MyApp());
//asyncFibonacci 函数里会创立一个 isolate,并返回运行后果
print(await asyncFibonacci(20));
}
// 这里以计算斐波那契数列为例,返回的值是 Future,因为是异步的
Future<dynamic> asyncFibonacci(int n) async{
// 首先创立一个 ReceivePort,为什么要创立这个?// 因为创立 isolate 所需的参数,必须要有 SendPort,SendPort 须要 ReceivePort 来创立
final response = new ReceivePort();
// 开始创立 isolate,Isolate.spawn 函数是 isolate.dart 里的代码,_isolate 是咱们本人实现的函数
//_isolate 是创立 isolate 必须要的参数。await Isolate.spawn(_isolate,response.sendPort);
// 获取 sendPort 来发送数据
final sendPort = await response.first as SendPort;
// 接管音讯的 ReceivePort
final answer = new ReceivePort();
// 发送数据
sendPort.send([n,answer.sendPort]);
// 取得数据并返回
return answer.first;
}
// 创立 isolate 必须要的参数
void _isolate(SendPort initialReplyTo){final port = new ReceivePort();
// 绑定
initialReplyTo.send(port.sendPort);
// 监听
port.listen((message){
// 获取数据并解析
final data = message[0] as int;
final send = message[1] as SendPort;
// 返回后果
send.send(syncFibonacci(data));
});
}
int syncFibonacci(int n){return n < 2 ? n : syncFibonacci(n-2) + syncFibonacci(n-1);
}
因为 Root isolate 会负责渲染,还有 UI 交互,如果咱们有一个很耗时的操作呢?后面晓得 isolate 里是一个 event loop(事件循环),如果一个很耗时的 task 始终在运行,那么前面的 UI 操作都被阻塞了,所以如果咱们有耗时的操作,就应该放在 isolate 里!
Stream(流)
什么是流?
- 这个大机器就是 StreamController,它是创立流的形式之一。
- StreamController 有一个入口,叫做 sink
- sink 能够应用 add 办法放货色进来,放进去当前就不再关怀了。
- 当有货色从 sink 进来当前,咱们的机器就开始工作
- StreamController 有一个进口,叫做 stream
- 机器处理完毕后就会把产品从进口丢进去,然而咱们并不知道什么时候会进去,所以咱们须要应用 listen 办法始终监听这个进口
- 而且当多个物品被放进来了之后,它不会打乱程序,而是先入先出
应用 Stream
StreamController controller = StreamController();
// 监听这个流的进口,当有 data 流出时,打印这个 data
StreamSubscription subscription =
controller.stream.listen((data)=>print("$data"));
controller.sink.add(123);
// 输入:123
你须要将一个办法交给 stream 的 listen 函数,这个办法入参 (data) 是咱们的 StreamController 处理完毕后产生的后果,咱们监听进口,并取得了这个后果(data)。这里能够应用 lambda 表达式,也能够是其余任何函数
transform
如果你须要更多的管制转换,那么请应用 transform()办法。他须要配合 StreamTransformer 进行应用。
StreamController<int> controller = StreamController<int>();
final transformer = StreamTransformer<int,String>.fromHandlers(handleData:(value, sink){if(value==100){sink.add("你猜对了");
}
else{sink.addError('还没猜中,再试一次吧');
}
});
controller.stream
.transform(transformer)
.listen((data) => print(data),
onError:(err) => print(err));
controller.sink.add(23);
//controller.sink.add(100);
// 输入:还没猜中,再试一次吧
StreamTransformer<S,T> 是咱们 stream 的检查员,他负责接管 stream 通过的信息,而后进行解决返回一条新的流。
- S 代表之前的流的输出类型,咱们这里是输出一个数字,所以是 int。
- T 代表转化后流的输出类型,咱们这里 add 进去的是一串字符串,所以是 String。
- handleData 接管一个 value 并创立一条新的流并裸露 sink,咱们能够在这里对流进行转化
Stream 的品种
- “Single-subscription” streams 单订阅流
- “broadcast” streams 多订阅流
单订阅流
StreamController controller = StreamController();
controller.stream.listen((data)=> print(data));
controller.stream.listen((data)=> print(data));
controller.sink.add(123);
// 输入: Bad state: Stream has already been listened to. 单订阅流不能有多个收听者。
单个订阅流在流的整个生命周期内仅容许有一个 listener
多订阅流
StreamController controller = StreamController();
// 将单订阅流转化为播送流
Stream stream = controller.stream.asBroadcastStream();
stream.listen((data)=> print(data));
stream.listen((data)=> print(data));
controller.sink.add(123);
// 输入:123 123
播送流容许任意数量的收听者,且无论是否有收听者,他都能产生事件。所以中途进来的收听者将不会收到之前的音讯。
参考深刻理解 isolate
永恒原文地址 flutter 异步编程