精华 Async/Await & Generator
发布于 4 年前 作者 iwillwen 3820 次浏览 来自 分享

Async Function = A, Generator = G, A ≠ G, ∃A ∈ G, ∃G ∈ A

Generator 我就不再介紹了,大家的用法看 Koa/co,真正意義看 https://zhuanlan.zhihu.com/p/20794401

我們來說說 async/await,自從 TJ 創造了 co 以後,一眾 JavaScript Diaosiloper 就瘋狂起來了:WOW,可以直接寫同步代碼了!

後來 async/await 進入 ECMAScript 的 Draft,是的,到今天為止還沒有成為標準。就有人覺得,這不就是 co 的東西嗎?嗯,可以說 co 就是模仿 async/await 來創造的。這裡又要說到什麼是“協程”了,對不起,JavaScript 暫時並沒有資格說這個,所以我以 Go 語言來講講吧。

package main

import "fmt"

func Add(x, y int, ch chan int) {
  z := x + y
  
  ch <- z
}

func main() {
  chs := make([]chan int, 10)
  for i := 0; i < 10; i++ {
    chs[i] := make(chan int)
    go Add(i, i + 1, chs[i])
  }
  
  for _, ch := range(chs) {
    val := <- ch // Waiting each coroutine to finish
    fmt.Println(val)
  }
}

Go 語言中利用 go 語句來將一個函數(Add)作為協程的運行內容創建一個協程,并通過 channel 特性來作為主線程與協程之間的通訊通道,因為 channel 的寫入和讀取具有原子性且同步的,所以如果協程內對 channel 的寫入並沒有完成,主線程中的讀取就會一直等待。

這樣的好處是,可以將複雜的、耗時長的、甚至堵塞的代碼放在協程中運行,而主線程中只要在需要的時候把結果取出來便可以了。這就是協程的意義,OK。


迴歸正題,async/await 跟 Generator 究竟有什麼差別?首先你要明白一點,兩者都可以完成類似於協程的任務。而如果非要說之間的差別,我可以這樣總結:

Async Function is a common function, Generator Function is not.

這話題一開始我就說了:

Async Function = A, Generator = G, A ≠ G, ∃A ∈ G, ∃G ∈ A

那麼在什麼情況下,他們之間存在包含關係呢?

Async Function ∈ (Generator + co)

是的,當 Generator 結合 co 時,Async Function 就變成了他們的子集,這就是 co 厲害的地方。

當然,這是在 Node.js 中的情況。那麼在前端開發中,情況又會是怎麼樣的呢?


我們知道前端開發需要響應用戶的操作事件,最基本就是點擊。假設有這樣一個場景,用戶在 input 中輸入一個 key,然後響應函數中需要從 MinDB 中讀取相應 key 的數據,并顯示在頁面上。

<div id="app">
  <input type="text" v-model="key">
  <p>{{value}}</p>
  <button @click="query">Query</button>
</div>

<script>
  import Vue from 'vue'
  import min from 'min'

  new Vue({
    el: '#app',

    data: {
      key: '',
      value: ''
    },

    methods: {
      query() {
        min.get(this.key)
          .then(value => this.value)
      }
    }
  })
</script>

我們可以看到 MinDB 的數據讀取是異步的,而且使用的是 Promise,那麼自然就想到了可不可以通過技術手段來變成“同步代碼”呢?

我們直接來看 async/await 吧。

methods: {
  async query() {
    this.value = await min.get(this.key)
  }
}

好的,完事了。如果用 Generator 呢?

methods: {
  query: function* () {
    this.value = yield min.get(this.key)
  }
}

嗯,看上去也不錯,但是運行之後便發現,沒報錯、也沒結果。為什麼?因為 Generator 並沒有運行起來。用 co 吧?

methods: {
  query() {
    const self = this
    co(function* () {
       self.value = yield min.get(self.key)
    })
  }
}

ok,其餘自己想吧。

7 回复

发现论坛中讨论 async/await 和 yield 的多起来了,支持技术贴。

赞一个。 但是拿一个未来的标准从语法上支持的东西(async/ await),跟一个现有标准不支持需要开发者自己造轮子来模仿从而难免看起来不太优雅的东西(co)来比较好坏,公平吗?

@htoooth 去年是Promise,今年这个!不知道标准出来以后,js程序猿是不是还需要理解怎么实现async/await,只管用?

就是这繁体字看起来有点晕

@DevinXian await和async也是promise和co的语法糖,学什么都不会白学的 From Noder

好久没有冒泡了,但是看到这篇文章我觉得还是有必要说两句的。 我不知道这篇文章怎么会加精了,这篇文章给我的感觉就是作者没有深刻认识协程以及对async/await与generator的区别。 说白点就是浅尝辄止。全篇给我一种什么都说但是什么都没说的感觉。另外,这又不是算法之类的,你又用了各种数学符号,感觉好高深的样子。 你在文章里说: Async_Await___Generator_-_CNode技术社区.png

你这段英语把有些关键性的解释一带而过,你应该解释一些generator函数是什么,执行方式与普通函数有什么区别,返回的形式又与普通函数有什么区别。虽然你可能清楚,但是最好还是明确的写出来。

Mozilla关于generator的解释

关于协程,你自己的通俗解释: Async_Await___Generator_-_CNode技术社区.png 你首先解释的是什么是协程,我个人的理解就是,多个线程完成一件事。 在JavaScript中,这都是事件循环,比如拿数据库中的数据,都是通过事件循环来一步步的进行下去的,而在JavaScript的协程当中,主进程拿线程处理好的数据也是通过事件循环,但是主进程是被通知被去拿,而不是主动,主动的那叫轮询。

最后

你整篇文章二分之一以上都是无关内容,此回复仅是对这篇文章内容而言,不对作者本人(我也不认识, 哈哈);

回到顶部