Dart 異步模型

Dart彙總請點擊這裏

Future

Future模型是將異步請求和代理模式結合的產物。
Future類是對未來結果的一個代理,它返回的並不是被調用的任務的返回值。

//我的任務
void  myTask(){
    print("this is my task");
}

void  main() {
    Future fut = new  Future(myTask);//根據我的任務創建Future對象
}

如上代碼,Future類實例fut並不是函數myTask的返回值,它只是代理了myTask函數,封裝了該任務的執行狀態。換種理解方式就是,Future就是一個受你委託的委託人,你將未來要執行的任務交給他,你告知他任務類型是耗時任務,還是非耗時任務,然後分類放到事件循環中去,當任務完成後,它會第一時間執行回調方法告知你任務完成,或者會等到你委託給他的所有任務都完成了立馬告知你。

創建Future

Future的幾種創建方法

Future()
Future.microtask()
Future.sync()
Future.value()
Future.delayed()
Future.error()

其中sync是同步方法,任務會被立即執行

import  'dart:async';

void  main() {
    print("main start");

new  Future.sync((){
    print("sync task");
});

new  Future((){
    print("async task");
});

    print("main stop");
}

運行結果:

main start
sync task
main stop
async task

註冊回調

使用then註冊回調

當Future中的任務完成後,我們往往需要一個回調,這個回調立即執行,不會被添加到事件隊列。

import 'dart:async';

void main() {
  print("main start");

  Future fut =new Future.value(18);
  // 使用then註冊回調
  fut.then((res){
    print(res);
  });

 // 鏈式調用,可以跟多個then,註冊多個回調
  new Future((){
    print("async task");
  }).then((res){
    print("async task complete");
  }).then((res){
    print("async task after");
  });

  print("main stop");
}

運行結果:

main start
main stop
18
async task
async task complete
async task after

除了then方法,還可以使用catchError來處理異常,如下

  new Future((){
    print("async task");
  }).then((res){
    print("async task complete");
  }).catchError((e){
    print(e);
  });

還可以使用靜態方法wait 等待多個任務全部完成後回調。

import 'dart:async';

void main() {
  print("main start");

  Future task1 = new Future((){
    print("task 1");
    return 1;
  });

  Future task2 = new Future((){
    print("task 2");
    return 2;
  });
    
  Future task3 = new Future((){
    print("task 3");
    return 3;
  });

  Future fut = Future.wait([task1, task2, task3]);
  fut.then((responses){
    print(responses);
  });

  print("main stop");
}

運行結果:

main start
main stop
task 1
task 2
task 3
[1, 2, 3]

如上,wait返回一個新的Future,當添加的所有Future完成時,在新的Future註冊的回調將被執行。

Future的特點

  • Future中的then並沒有創建新的Event丟到Event Queue中,而只是一個普通的Function Call,在FutureTask執行完後,立即開始執行

  • Future如果在then()調用之前Future就已經執行完畢了,那麼會有一個任務被加入到microtask隊列中。這個任務執行的就是被傳入then的方法

  • Future只是創建了一個Event,將Event插入到了Event Queue的隊尾

  • Future.value創建Task到microtask Queue中執行then傳入的函數

  • Future.sync執行了它傳入的函數之後,也會立即創建Task丟到microtask Queue中執行

  • Future.wait等待多個任務全部完成後回調。wait返回一個新的Future,當添加的所有Future完成時,在新的Future註冊的回調將被執行。

  • Future.delayed在延時一定時間後向隊列插入一個任務
    雖然可以預測任務執行的順序,但是我們無法預測事件循環什麼時候會從隊列中提取任務。Dart事件處理系統基於單線程循環,而不是基於時基(tick,系統的相對時間單位)或者其他的時間度量。例如,當你創建一個延時1s的任務,1s後向事件隊列添加一個任務,但在該任務之前的任務結束前,事件循環是不會處理這個任務的,也就是說該任務執行可能是大於1s的。

async 和 await

在Dart1.9中加入了async和await關鍵字,有了這兩個關鍵字,我們可以更簡潔的編寫異步代碼,而不需要調用Future相關的API。他們允許你像寫同步代碼一樣寫異步代碼和不需要使用Future接口。

將 async 關鍵字作爲方法聲明的後綴時,具有如下意義

被修飾的方法會將一個 Future 對象作爲返回值
該方法會同步執行其中的方法的代碼直到第一個 await 關鍵字,然後它暫停該方法其他部分的執行;
一旦由 await 關鍵字引用的 Future 任務執行完成,await的下一行代碼將立即執行。

// 導入io庫,調用sleep函數
import 'dart:io';

// 模擬耗時操作,調用sleep函數睡眠2秒
doTask() async{
  await sleep(const Duration(seconds:2));
  return "Ok";
}

// 定義一個函數用於包裝
test() async {
  var r = await doTask();
  print(r);
}

void main(){
  print("main start");
  test();
  print("main end");
}

運行結果:

main start
main end
Ok

注意:需要注意,async 不是並行執行,它是遵循Dart 事件循環規則來執行的,它僅僅是一個語法糖,簡化Future API的使用。

Future 原理

Dart 是事件驅動的體系結構,該結構基於具有單個事件循環兩個隊列的單線程執行模型。 Dart雖然提供調用堆棧。 但是它使用事件在生產者和消費者之間傳輸上下文。 事件循環由單個線程支持,因此根本不需要同步和鎖定。
詳細請參閱我的另一篇文章: Dart 事件循環

使用 Future 控制任務調度

將任務添加到MicroTask隊列立即執行或將任務添加到Event隊列空閒執行
詳細請參閱我的另一篇文章:Dart 任務調度

發佈了80 篇原創文章 · 獲贊 44 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章