前言
接觸過Flutter的人都知道,Flutter是用Dart來寫的,Dart沒有程式和執行緒的概念,所有的Dart程式碼都是在isolate上執行的,那麼isolate到底是什麼?本系列的文章將詳細討論。這篇文章討論事件佇列(event loop)及Dart程式碼執行順序。
0x00 同步程式碼和非同步程式碼
我們對Dart程式碼進行分類:同步程式碼和非同步程式碼; 我們在寫Dart程式碼的時候,就只有兩種程式碼,
- 同步程式碼:就是一行行寫下來的程式碼
- 非同步程式碼:就是以Future等修飾的程式碼
這兩類程式碼是不同的:
1.執行順序不同
同步程式碼和非同步程式碼執行的順序是不同的:
先執行同步程式碼,在執行非同步程式碼
複製程式碼
就是,即使我非同步程式碼寫在最前面,同步程式碼寫在最後面,不好意思,我也是先執行後面的同步程式碼,同步程式碼都執行完後,在執行前面的非同步程式碼。
2.執行的機制不同
非同步程式碼是執行在event loop
裡的,這是一個很重要的概念,這裡可以理解成Android裡的Looper機制,是一個死迴圈,event loop
不斷的從事件佇列裡取事件然後執行。
0x01 event loop 架構
下面是event loop大致的執行圖:
這個很好理解,事件events加到Event queue裡,Event loop迴圈從Event queue裡取Event執行。這個理解後,在看event loop詳細的執行圖:
從這裡看到,啟動app(start app)後:
- 先檢視MicroTask queue是不是空的,不是的話,先執行microtask
- 一個microtask執行完後,會看有沒有下一個microtask,直到Microtask queue空了之後,才會去執行Event queue 3.在Evnet queue取出一個event task執行完後,又會跑到第一步,去執行microtask
這裡多了兩個名詞:MicroTask
和Event
,這代表了兩個不同的非同步task
而且可以看出:
- 如果想讓任務能夠儘快執行,就用
MicroTask
1. MicroTask
這個大家應該不太清楚,但是這個也是dart:async
提供的非同步方法,使用方式:
// Adds a task to the 先檢視MicroTask queue.
scheduleMicrotask((){
// ...code goes here...
});
複製程式碼
或者:
new Future.microtask((){
// ...code goes here...
});
複製程式碼
2.Event
Event我們就很清楚了,就是Future修飾的非同步方法,使用方式:
// Adds a task to the Event queue.
new Future(() {
// ...code goes here...
});
複製程式碼
0x02
純粹講理論知識不太好理解,我們直接上程式碼,講一個例子,看如下的程式碼,請問列印順序是什麼樣的?
import 'dart:async';
void main() {
print('main #1 of 2');
scheduleMicrotask(() => print('microtask #1 of 3'));
new Future.delayed(new Duration(seconds:1),
() => print('future #1 (delayed)'));
new Future(() => print('future #2 of 4'))
.then((_) => print('future #2a'))
.then((_) {
print('future #2b');
scheduleMicrotask(() => print('microtask #0 (from future #2b)'));
})
.then((_) => print('future #2c'));
scheduleMicrotask(() => print('microtask #2 of 3'));
new Future(() => print('future #3 of 4'))
.then((_) => new Future(
() => print('future #3a (a new future)')))
.then((_) => print('future #3b'));
new Future(() => print('future #4 of 4'))
.then((_){
new Future(() => print('future #4a'));
})
.then((_) => print('future #4b'));
scheduleMicrotask(() => print('microtask #3 of 3'));
print('main #2 of 2');
}
複製程式碼
-
首先執行同步程式碼
所以是:
main #1 of 2 main #2 of 2 複製程式碼
-
接下來是非同步程式碼
Dart的Event Loop是先判斷
microtask queue
裡有沒有task,有的話執行microtask
,microtask
執行完後,在執行event queue
裡的event task
,一個event task
執行完後,再去執行microtask queue
,然後在執行event queue
。 -
microtask queue
這裡就是:
microtask #1 of 3 microtask #2 of 3 複製程式碼
-
event queue event queue還有有特殊的情況需要考慮:
-
Future.delayed
需要延遲執行的,Dart是怎麼執行的呢,是在延遲時間到了之後才將此task加到
event queue
的隊尾,所以萬一前面有很耗時的任務,那麼你的延遲task不一定能準時執行 -
Future.then
Future.then裡的task是不會加入到
event queue
裡的,而是當前面的Future執行完後立即掉起,所以你如果想保證非同步task的執行順序一定要用then,否則Dart不保證task的執行順序 -
scheduleMicrotask
一個
event task
執行完後,會先去檢視Micro queue
裡有沒有可以執行的micro task
。沒有的話,在執行下一個event task
這裡就是: ``` future #2 of 4 future #2a future #2b future #2c microtask #0 (from future #2b) future #3 of 4 future #4 of 4 future #4b future #3a (a new future) future #3b future #4a future #1 (delayed) ``` 複製程式碼
-
這裡你肯定好奇為啥future #3 of 4
後面是future #4 of 4
,而不是future #3a (a new future)
,因為 future #3 of 4
的then裡又新建了一個Future:future #3a (a new future)
,所以future #3a (a new future)
這個task會加到event queue
的最後面。
最後的結果就是:
main #1 of 2
main #2 of 2
microtask #1 of 3
microtask #2 of 3
microtask #3 of 3
future #2 of 4
future #2a
future #2b
future #2c
microtask #0 (from future #2b)
future #3 of 4
future #4 of 4
future #4b
future #3a (a new future)
future #3b
future #4a
future #1 (delayed)
複製程式碼