精华 Async/Await & Generator
发布于 10 天前 作者 iwillwen 585 次浏览 来自 分享

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,其餘自己想吧。

4 回复

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

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

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

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

回到顶部