美文网首页
Flutter线程进阶——深入async-await异步编程原理

Flutter线程进阶——深入async-await异步编程原理

作者: 码农的地中海 | 来源:发表于2022-07-06 21:19 被阅读0次

    async-await基本介绍

    async-await本质上是对Future API的简化形式,将异步回调代码写成同步代码结构形式。「async关键字修饰的函数总是返回一个Future对象,所以async并不会阻塞当前线程」,由前面的EventLoop和Future我们都知道Future的最终会加入EventQueue中,而EventQueue执行是当main函数执行完毕后,才会检查Microtask Queue和Event Queue并处理它们。「await关键字意味着中断当前代码执行流程直到当前的async方法执行完毕,如果没有执行完毕下面的代码将处于等待的状态」

    7cebffa6090efeda931d299034e2eb6c.jpeg

    为什么需要async-await

    通过学习之前异步编程中的Future我们知道,Future一般使用 thencatchError可以很好地处理数据回调和异常回调。这实际上还是一种基于异步回调的方式,如果异步操作依赖关系比较复杂需要编写回调代码比较繁杂,为了简化这些步骤 async-await关键字通过同步代码结构来实现异步操作,从而使得代码更加简洁和具有可读性,此外在异常处理方式也会变得更加简单。

    async await具体使用规则

    (1)async的函数在执行后都会自动返回一个Promise对象,有无值根据有无return值。

    (2)await必须在async函数里使用,不能单独使用。

    (3)await后面需要跟Promise对象,不然就没有意义,而且await后面的Promise对象不必写then,因为await的作用之一就是获取后面Promise对象成功状态传递出来的参数。

    (4)async/await作用是用同步方式,执行异步操作。

    generator函数

    (1)跟普通函数在写法上的区别就是,多了一个星号*

    (2) yield:只有在generator函数中才能使用yield。相当于generator函数执行的中途停站点。

    (3)next方法:执行后会返回一个对象,对象中有value和done两个属性。

    • value:暂停点后面接的值,也就是yield后面接的值(最后一个是undefined,这取决于generator函数有无返回值)
    • done:是否generator函数已走完,没走完为false,走完为true

    (4)generator函数可以用next方法来传参,并且可以通过yield来接收这个参数,注意两点

    • 第一次next传参是没用的,只有从第二次开始next传参才有用
    • next传值时,要记住顺序是,先右边yield,后左边接收参数
    function* gen() {
      const num1 = yield 1
      console.log(num1)
      const num2 = yield 2
      console.log(num2)
      return 3
    }
    const g = gen()
    console.log(g.next()) // { value: 1, done: false }
    console.log(g.next(11111))
    // 11111
    //  { value: 2, done: false }
    console.log(g.next(22222)) 
    // 22222
    // { value: 3, done: true }
    

    原理

    Future是Dart语法异步的核心,通过async标记一个方法为异步,返回一个future对象,进而对flutter进行监听,获取异步方法的返回值。一般用法为:

    Future<int> getCount async {
      ~~~~
      return count;
    }
    
    Future<int> future = getCount();
    
    getCount().then((value) {
      int res = value;
    });
    

    单个异步任务很好理解,代码写起来也很易读,但是多个异步任务协同工作时,这种写法会特别冗余且不易理解,例如:

    Future<int> _loadFromDisk(){}
    Future<String> _fetchNetworkData(){}
    
    Future<ProcessData> createData() {
      return _loadFromDisk().then((id) {
        return _fetchNetworkData(id);
      }).then((data) {
        return ProcessData(data);
      })
    }
    

    这个方法表示首先调用_loadFromDisk()方法,获取id后再调用_fetchNetworkData()方法,获取data后返回ProcessData,这个是两层嵌套的例子,倘若是3层、4层乃至更多层,代码将杂乱无章。

    为了针对这个问题,Dart引入了asyncawait机制,将异步嵌套的代码转换为类似同步代码的结构,极大的方便了编码效率和可读性,上面的两层嵌套等同于:

    ProcessData createData() async {
      int id = await _loadFromDisk();
      String data = await _fetchNetworkData(id)
      return ProcessData(data)
    }
    
    小结

    async标识一个方法为异步方法,返回的是一个Future对象,可以监听Future对象的返回值,也可以用then的方式等待异步方法执行完毕后继续执行一个方法,若有多个异步方法需要顺序执行,可以采用then嵌套的方式,但是层数较多时可读性极差,await可以理解为一个异步的语法糖,通过这种方式可以用类似同步的代码块实现异步方法的顺序执行,可读性很高。

    文末

    async、await的操作属于"假异步",这是为什么呢? 如果想要得到这个问题的答案,首先我们需要了解async、await的原理,了解协程的概念,因为async、await本质上就是协程的一种语法糖。协程,也叫作coroutine,是一种比线程更小的单元。如果从单元大小来说,基本可以理解为 进程->线程->协程。 更多Flutter线程知识,可前往实战混合式开发Flutter3.0手册进行系统性学习;以及Flutter高级工程师进阶。

    相关文章

      网友评论

          本文标题:Flutter线程进阶——深入async-await异步编程原理

          本文链接:https://www.haomeiwen.com/subject/hwaybrtx.html