一、Dart单线程

开发中,我们经常会遇到一些耗时的操作,比如网络请求、文件读取等;如果一直在等待这些耗时的操作完成,就会进行阻塞,无法响应其它事件,如点击、滑动。
如何处理耗时操作,不同的语言有不同的处理方式。

  • 多线程,如iOS,是开启一个新的线程,在新的线程中完成耗时操作,再通过线程间通信的方式,将数据传递给主线程。
  • 单线程+事件循环,如Dart基于单线程+事件循环来完成耗时操作。

单线程如何能进行耗时的操作呢?
首先我们了解什么阻塞式调用和非阻塞式调用的概念,通俗的讲,阻塞和非阻塞是等待程序返回结果时的状态。

  • 阻塞式调用:返回结果之前,当前线程会被挂起,程序只有在得到调用结果之后才会继续执行后面代码。
  • 非阻塞式调用:调用执行之后,当前线程不会被挂起,只需要过一段时间来检查一下有没有返回结果即可。

在生活中我们点外卖,点外卖的动作类似我们调用程序耗时操作,拿到外卖就是我们要等待的返回结果。

  • 阻塞式调用:点了外卖,不再做任何事情,干等着,停止任何其他的事情。
  • 非阻塞式调用:点了外卖,继续做其他的事情:工作、游戏,只需要看看有没有外卖电话即可。

其实一个应用程序大部分时间都是处于空闲的状态的,并不是无时无刻的与用户进行交互操作。像网络请求、文件读写等耗时操作,都可以基于非阻塞调用,并不会阻塞我们的线程,在等待的过程中可以继续去做其他的事情,等有了响应,再去进行处理即可。

二、Dart事件循环

首先我们要了解什么是事件循环,其实就是将需要处理的一系列事件(包括点击事件、IO事件、网络事件)放在一个事件队列中,然后不断的从事件队列中取出事件,并执行其对应需要执行的代码块,直到事件队列清空位置。
单线程就是通过事件循环来处理网络通信、文件读写操作的返回结果,主要在维护着一个事件循环。

事件循环的伪代码:

  1. // List模拟队列, 先进先出的原则
  2. List eventQueue = [];
  3. var event;
  4. // 事件循环从启动的一刻,永远在执行
  5. while (true) {
  6. if (eventQueue.length > 0) {
  7. // 取出一个事件
  8. event = eventQueue.removeAt(0);
  9. // 执行该事件
  10. event();
  11. }
  12. }

三、Dart异步操作

3.1 Future

3.1.1 同步请求

3.1.2 异步请求

3.1.3 Future使用

Future.then
Future.catchError
Future.whenComplete
Future.wait

3.2 await、async

3.2.1 什么是await、async

通过上面的学习,我们知道Future不阻塞线程,完成某个操作后回调then或者catchError。
生成一个Future方式:

  • 通过Future构造函数,或者Future其他API。
  • 通过async的函数,一个async的函数会返回一个Future。

Dart中使用await、async关键字,用同步的代码格式,实现异步的调用过程。

3.2.2 await、async使用