docs: 从 Flutter 和前端角度出发,聊聊单线程模型下如何保证 UI 流畅性

This commit is contained in:
杭城小刘
2021-06-20 22:06:58 +08:00
parent fd6372abb8
commit f996385a79

View File

@@ -33,7 +33,7 @@ void mainThread () {
线程开始执行任务,按照需求,单线程依次执行每个任务,执行完毕后线程马上退出。
![基础单线程模型]((https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/2021-06-18-SingleThread1.png)
![基础单线程模型](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/2021-06-18-SingleThread1.png)
@@ -67,7 +67,7 @@ void mainThread () {
- 引入了**循环机制**,线程不会做完事情马上退出。
- 引入了**事件**。线程一开始会等待用户输入,等待的时候线程处于暂停状态,当用户输入完毕,线程得到输入的信息,此时线程被激活。执行相加的操作,最终输出结果。不断的等待输入,并计算输出。
![]((https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/2021-06-18-SingleThread2.png)
![](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/2021-06-18-SingleThread2.png)
@@ -77,7 +77,7 @@ void mainThread () {
真实环境中的线程模块远远没有这么简单。比如浏览器环境下线程可能正在绘制可能会接收到1个来自用户鼠标点击的事件1个来自网络加载 css 资源完成的事件等等。第二版线程模型虽然引入了事件循环机制,可以接受新的事件任务,但是发现没?这些任务之来自线程内部,该设计是无法接受来自其他线程的任务的。
![第三版线程模型]((https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/2021-06-18-SingleThread3.png)
![第三版线程模型](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/2021-06-18-SingleThread3.png)
@@ -89,13 +89,13 @@ void mainThread () {
![事件队列]((https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/2021-06-18-SingleThread4.png)
![事件队列](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/2021-06-18-SingleThread4.png)
**消息队列(事件队列)是一种合理的数据结构。要执行的任务添加到队列的尾部,需要执行的任务,从队列的头部取出。**
有了消息队列之后,线程模型得到了升级。如下:
![单线程模型第四版]((https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/2021-06-18-SingleThread5.png)
![单线程模型第四版](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/2021-06-18-SingleThread5.png)
@@ -143,7 +143,7 @@ Tips: 事件队列是存在多线程访问的情况,所以需要加锁。
### 4. 处理来自其他线程的任务
![单线程模型+跨进程任务]((https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/2021-06-19-SingleThread6.png)
![单线程模型+跨进程任务](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/2021-06-19-SingleThread6.png)
浏览器环境中 渲染进程经常接收到来自其他进程的任务IO 线程专门用来接收来自其他进程传递来的消息。IPC 专门处理跨进程间的通信。
@@ -185,7 +185,7 @@ Chrome 设计上,确定要退出当前页面时,页面主线程会设置一
- 如何解决单个任务执行时间过长的问题
![卡顿]((https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/2021-06-19-SingleThread7.png)
![卡顿](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/2021-06-19-SingleThread7.png)
可以看出,假如 JS 计算超时导致动画 paint 超时,会造成卡顿。浏览器为避免该问题,采用 callback 回调的设计来规避,也就是让 JS 任务延后执行。
@@ -201,7 +201,7 @@ Dart 是单线程的,也就是代码会有序执行。此外 Dart 作为 Flutt
一个 Flutter 应用包含一个或多个 **isolate**,默认方法的执行都是在 **main isolate** 中;**一个 isolate 包含1个 Event loop 和1个 Task queue。其中Task queue 包含1个 Event queue 事件队列和1个 MicroTask queue 微任务队列**。如下:
![Flutter Event Loop]((https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/FlutterSingleThread1.png)
![Flutter Event Loop](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/FlutterSingleThread1.png)
为什么需要异步?因为大多数场景下 应用都并不是一直在做运算。比如一边等待用户的输入,输入后再去参与运算。这就是一个 IO 的场景。所以单线程可以再等待的时候做其他事情,而当真正需要处理运算的时候,再去处理。因此虽是单线程,但是给我们的感受是同事在做很多事情(空闲的时候去做其他事情)
@@ -215,7 +215,7 @@ Dart 中存在2个队列一个微任务队列Microtask Queue、一个
Event loop 不断的轮询先判断微任务队列是否为空从队列头部取出需要执行的任务。如果微任务队列为空则判断事件队列是否为空不为空则从头部取出事件比如键盘、IO、网络事件等然后在主线程执行其回调函数如下
![Flutter 单线程模型]((https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/2021-06-20-FlutterSingleThread2.png)
![Flutter 单线程模型](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/2021-06-20-FlutterSingleThread2.png)
### 2. 异步任务