Dart入門07 -- 異步

  • 在Dart中處理耗時(shí)操作(網(wǎng)絡(luò)請求,文件讀取),采用的的處理方式為單線程 + 事件循環(huán),而在OC,Java中采用的是多線程;

阻塞式調(diào)用與非阻塞式調(diào)用

  • 其是操作系統(tǒng)中的概念;
  • 其關(guān)注的是程序在等待調(diào)用結(jié)果時(shí)的狀態(tài);
  • 阻塞式調(diào)用:在調(diào)用結(jié)果返回之前,當(dāng)前線程會(huì)被掛起,調(diào)用線程只有在得到調(diào)用結(jié)果之前才能繼續(xù)執(zhí)行;
  • 非阻塞式調(diào)用:調(diào)用執(zhí)行之后,當(dāng)前線程不會(huì)停止執(zhí)行,只需要過一段時(shí)間來檢查一下有沒有結(jié)果返回即可;

Dart事件循環(huán)

  • 事件循環(huán):其將需要處理的一系列事件(包括點(diǎn)擊事件,IO事件,網(wǎng)絡(luò)事件)放在一個(gè)事件隊(duì)列中,然后不斷的從事件隊(duì)列中取出事件,并執(zhí)行其對應(yīng)需要執(zhí)行的代碼塊,直到事件隊(duì)列清空位置;

Dart的異步操作

  • Dart的異步操作有三種,分別為:Future,async和await;
Future
  • Future就是一個(gè)受你委托的委托人,你將未來要執(zhí)行的任務(wù)交給他,你告知他任務(wù)類型是耗時(shí)任務(wù),還是非耗時(shí)任務(wù),然后分類放到事件循環(huán)中去,當(dāng)任務(wù)完成后,它會(huì)第一時(shí)間執(zhí)行回調(diào)方法告知你任務(wù)完成,或者會(huì)等到你委托給他的所有任務(wù)都完成了立馬告知你;
  • Future可以看成是包裝task任務(wù)的;
  • Future的創(chuàng)建方式有如下幾種方式:
    • new Future(task函數(shù)) 異步 task任務(wù)會(huì)延遲執(zhí)行;
    • new Future.sync(task函數(shù)) 同步 task任務(wù)會(huì)立即執(zhí)行;
    • new Future.delayed(延遲時(shí)間,task任務(wù)) 延遲執(zhí)行task任務(wù);
  • 案例代碼如下:
void main(List<String> args) {
  print("main 函數(shù)開始執(zhí)行");
  //根據(jù)任務(wù)創(chuàng)建Future
  Future future1 = new Future(Task);

  Future future = new Future.sync(() {
    print("同步任務(wù)執(zhí)行");
  });

  Future future2 = new Future(() {
    print("task2 執(zhí)行");
  });

  print("main函數(shù)結(jié)束執(zhí)行");
}

void Task() {
  print("task1 執(zhí)行");
}
  • 控制臺(tái)執(zhí)行結(jié)果如下:
image.png
void main(List<String> args) {
  print("main函數(shù)開始執(zhí)行");
  Future future = new Future.delayed(Duration(seconds: 2), () {
    print("任務(wù)延遲2秒后 開始執(zhí)行");
  });
  print("main函數(shù)結(jié)束執(zhí)行");
}
  • 控制臺(tái)打印結(jié)果:
image.png
  • Future注冊回調(diào),當(dāng)耗時(shí)任務(wù)執(zhí)行完成后,會(huì)執(zhí)行回調(diào)函數(shù),注冊回調(diào)有如下幾種方式:
    • then回調(diào):當(dāng)Future中的任務(wù)完成后,我們往往需要一個(gè)回調(diào),這個(gè)回調(diào)立即執(zhí)行,不會(huì)被添加到事件隊(duì)列,then回調(diào)可支持多個(gè)回調(diào);
    • catchError回調(diào):可用來處理異常;
    • 靜態(tài)方法wait:等待多個(gè)任務(wù)全部完成后回調(diào);
  • then回調(diào),案例代碼如下:
void main(List<String> args) {
  print("main函數(shù)開始執(zhí)行");
  Future future = new Future(() {
    print("task 執(zhí)行");
  });

  future.then((value) {
    print("task 執(zhí)行完成的回調(diào)");
  });
  print("main函數(shù)結(jié)束執(zhí)行");
}
  • 控制臺(tái)打印結(jié)果:
image.png
  • then支持多個(gè)回調(diào),案例代碼如下:
void main(List<String> args) {
  print("main函數(shù)開始執(zhí)行");
  Future future = new Future(() {
    print("task 執(zhí)行");
  });

  future.then((value) {
    print("task 執(zhí)行完成的回調(diào)");
  }).then((value) {
    print("task 回調(diào)完成之后");
  });
  print("main函數(shù)結(jié)束執(zhí)行");
}
  • 控制臺(tái)打印結(jié)果如下:
image.png
  • catchError回調(diào),案例代碼如下:
void main(List<String> args) {
  print("main函數(shù)開始執(zhí)行");
  new Future(() {
    print("task 任務(wù)");
  }).then((value) {
    print("task 任務(wù)執(zhí)行完成的回調(diào)");
  }).then((value) {
    print("task 回調(diào)完成之后的處理");
  }).catchError((e) {
    print("task 任務(wù)執(zhí)行出現(xiàn)異常的回調(diào)");
  });
  print("main函數(shù)結(jié)束執(zhí)行");
}
  • 靜態(tài)方法wait,多個(gè)異步耗時(shí)操作同時(shí)執(zhí)行,結(jié)果統(tǒng)一處理,案例代碼如下:
void main(List<String> args) {
  print("main函數(shù)開始執(zhí)行");
  Future future1 = new Future(() {
    print("task1");
    return 1;
  });

  Future future2 = new Future(() {
    print("task2");
    return 2;
  });

  Future future3 = new Future(() {
    print("task3");
    return 3;
  });

  Future future = Future.wait([future1, future2, future3]);
  future.then((value) {
    print(value);
  });

  print("main函數(shù)結(jié)束執(zhí)行");
}
  • 控制臺(tái)打印結(jié)果如下:
image.png
  • wait函數(shù)返回一個(gè)新的Future,當(dāng)添加的所有Future完成時(shí),會(huì)在新的Future注冊的回調(diào)將被執(zhí)行;
await 與 async
  • 在Dart1.9中加入了async和await關(guān)鍵字,有了這兩個(gè)關(guān)鍵字,我們可以更簡潔的編寫異步代碼,而不需要調(diào)用Future相關(guān)的API;
  • 將 async 關(guān)鍵字作為方法聲明的后綴時(shí),具有如下意義:
    • 被修飾的方法會(huì)將一個(gè) Future 對象作為返回值;
    • 該方法會(huì) 同步執(zhí)行 其中的方法的代碼 直到第一個(gè) await 關(guān)鍵字,然后它暫停該方法其他部分的執(zhí)行;
    • 一旦由 await 關(guān)鍵字引用的 Future 任務(wù)執(zhí)行完成,await的下一行代碼將立即執(zhí)行;
  • 實(shí)現(xiàn)請求的依賴,順序執(zhí)行,案例代碼如下:
import 'dart:io';

main(List<String> args) {
  print("main start");

  getData();

  print("main end");
}

void getData() async {
  //鏈?zhǔn)秸{(diào)用
  var res1 = await getNetworkData("SF");
  print(res1);
  var res2 = await getNetworkData(res1);
  print(res2);
  var res3 = await getNetworkData(res2);
  print(res3);
}

//異步函數(shù)
//1.await必須在async函數(shù)中才能使用
//2.async函數(shù)返回的結(jié)果必須是一個(gè)Future
Future getNetworkData(String str) {
  return Future(() {
    sleep(Duration(seconds: 3));
    return "Hello World!!" + str;
  });
}
  • 控制臺(tái)打印結(jié)果如下:
image.png
  • await必須在async函數(shù)中才能使用;
  • async函數(shù)返回的結(jié)果必須是一個(gè)Future;
  • 實(shí)現(xiàn)多個(gè)請求異步執(zhí)行,回調(diào)結(jié)果統(tǒng)一處理,案例代碼如下:

多核CPU的利用

Isolate
  • Dart是單線程的,這個(gè)線程有自己可以訪問的內(nèi)存空間以及需要運(yùn)行的事件循環(huán);
  • 我們可以將這個(gè)空間系統(tǒng)稱之為是一個(gè)Isolate;
  • 例如Flutter中就有一個(gè)Root Isolate,負(fù)責(zé)運(yùn)行Flutter代碼,比如UI渲染,用戶交互等等;
  • 在Isolate中,資源隔離做的非常好,每個(gè)Isolate都有自己的事件循環(huán)與事件隊(duì)列,Isolate之間之間不共享任何資源,只能依靠消息機(jī)制進(jìn)行通信,因此也就沒有資源搶占問題,但是如果只有一個(gè)Isolate,那么意味著我們只能永遠(yuǎn)利用一個(gè)線程,這對于多核CPU來說,是一種資源的浪費(fèi);
Isolate的創(chuàng)建
  • 案例代碼:
import 'dart:isolate';

main(List<String> args) {
  print("main start");
  //不會(huì)阻塞當(dāng)前線程 
  Isolate.spawn(calc, 100);

  print("main end");
}

void calc(int count) {
  var total = 0;
  for (var i = 0; i < count; i++) {
    total += I;
  }
  print(total);
}
Isolate的通信機(jī)制
  • 創(chuàng)建新的Isolate用于處理耗時(shí)操作,然后將耗時(shí)操作的結(jié)果告知Main Isolate(也就是默認(rèn)開啟的Isolate);
  • Isolate通過發(fā)送管道(SendPort)實(shí)現(xiàn)消息通信機(jī)制;
  • 我們可以在啟動(dòng)并發(fā)Isolate時(shí)將Main Isolate的發(fā)送管道作為參數(shù)傳遞給它;
  • 并在執(zhí)行完畢時(shí),可以利用這個(gè)管道給Main Isolate發(fā)送消息;
  • 案例代碼:
import 'dart:isolate';

main(List<String> args) async {
  print("main start");

  //1.創(chuàng)建管道
  ReceivePort port = ReceivePort();

  //2.創(chuàng)建Isolate
  Isolate isolate = await Isolate.spawn<SendPort>(foo, port.sendPort);

  //3.監(jiān)聽管道
  port.listen((message) {
    print(message);
    //關(guān)閉管道
    port.close();
    //Isolate銷毀
    isolate.kill();
  });

  print("main end");
}

void foo(SendPort port) {
  return port.send("Hello World");
}
第三方網(wǎng)絡(luò)請求庫
  • Dio的引入,如下所示:
image.png
  • 在網(wǎng)絡(luò)請求庫Dio的基礎(chǔ)上進(jìn)行封裝,創(chuàng)建了http_config.darthttp_request.dart兩個(gè)文件,如下所示:
class HttpConfig {
  static const String baseUtl = "http://httpbin/org";
  static const int timeout = 5000;
}
import 'package:Fluter01/service/http_config.dart';
import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';

class HttpReuquest {
  //基礎(chǔ)配置
  static final BaseOptions baseOptions = BaseOptions(baseUrl: HttpConfig.baseUtl,connectTimeout: HttpConfig.timeout);
  //網(wǎng)絡(luò)請求
  static final Dio dio = Dio(baseOptions);

  static Future<T> request<T>(String url,{String method = "get",Map<String,dynamic> params,Interceptor interceptor}) async{
    //配置
    final options = Options(method: method);

    //全局?jǐn)r截器
    Interceptor dInterceptor = InterceptorsWrapper(
        onRequest: (options){
          print("請求攔截");
          return options;
        },
        onResponse: (response) {
          print("響應(yīng)攔截");
          return response;
        },
        onError: (error){
          print("錯(cuò)誤攔截");
          return error;
        }
    );

    List<Interceptor> inters = [dInterceptor];

    //單獨(dú)設(shè)置的攔截器
    if (interceptor != null){
      inters.add(interceptor);
    }

    dio.interceptors.addAll(inters);

    //發(fā)送網(wǎng)絡(luò)請求
    try {
      Response response = await dio.request(url,queryParameters: params,options: options);
      return response.data;
    } on DioError catch(e) {
      return Future.error(e);
    }
  }
}
  • 使用封裝的網(wǎng)絡(luò)請求類:
import 'package:flutter/material.dart';
import 'package:Fluter01/service/http_request.dart';

void main() => runApp(SFMyApp());

class SFMyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: SFHomePage());
  }
}

class SFHomePage extends StatefulWidget {
  @override
  _SFHomePageState createState() => _SFHomePageState();
}

class _SFHomePageState extends State<SFHomePage> {
  bool isShowFloatButton = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("基礎(chǔ)widget")),
      body: SFHomeContent(),
      floatingActionButton: isShowFloatButton
          ? FloatingActionButton(
              child: Icon(Icons.arrow_upward),
              onPressed: () {

              },
            )
          : null,
    );
  }
}

class SFHomeContent extends StatefulWidget {
  @override
  _SFHomeContentState createState() => _SFHomeContentState();
}

class _SFHomeContentState extends State<SFHomeContent> {

  @override
  void initState() {
    super.initState();

    //發(fā)送網(wǎng)絡(luò)請求
    // ///1.創(chuàng)建dio對象
    // final dio = Dio();
    // ///2.發(fā)送網(wǎng)絡(luò)請求
    // dio.get("http://httpbin.org/get").then((value) {
    //   print(value);
    // });
    
    HttpReuquest.request("http://httpbin.org/get",params: {"name" : "liyanyan"}).then((value) {
      print(value);
    });
    
    
  }

  @override
  Widget build(BuildContext context) {
    return NotificationListener(
      onNotification: (ScrollNotification notification){
        if(notification is ScrollStartNotification){
          print("開始滾動(dòng)");
        }else if (notification is ScrollUpdateNotification){
          print("正在滾動(dòng) -- 總區(qū)域:${notification.metrics.maxScrollExtent} 當(dāng)前位置: ${notification.metrics.pixels}");
        }else if (notification is ScrollEndNotification){
          print("結(jié)束滾動(dòng)");

        }
        return true;
      },
      child: ListView.builder(
        itemBuilder: (BuildContext ctx, int index) {
          return ListTile(
            leading: Icon(Icons.people),
            title: Text("聯(lián)系人$index"),
          );
        },
        itemCount: 100,
      ),
    );
  }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容