事件循环、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;//接管音讯的ReceivePortfinal 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流出时,打印这个dataStreamSubscription 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异步编程