[譯] JavaScript - Generator-Yield/Next 和 Async-Await

Generator (ES6)javascript

generator 函數是一個能夠根據用戶需求,在不一樣的時間間隔返回多個值,並能管理其內部狀態的函數。若是一個函數使用了 function* 語法,那麼它就變成了一個 generator 函數。前端

它們與正常函數不一樣,正常函數在單次執行中完成運行,而 generator 函數能夠被暫停和恢復。它們確實會運行完成,但觸發器在咱們手中。它們使得對異步函數能有更好的執行控制,但這並不意味着它們不能用做同步函數。java

注意:執行 generator 函數時,會返回一個新的 Generator 對象。node

generator 的暫停和恢復是使用 yieldnext 完成的。讓咱們來看看它們是什麼,以及它們能作什麼。android

Yield/Next

yield 關鍵字暫停 generator 函數的執行,而且 yield 關鍵字後面的表達式的值將返回給 generator 的調用者。它能夠被理解爲基於 generator 版本的 return 關鍵字。ios

yield 關鍵字實際上返回一個具備 valuedone 兩個屬性的 IteratorResult 對象。(若是你不瞭解什麼是 iterators 和 iterables,點擊這裏閱讀)。git

一旦暫停 yield 表達式,generator 的代碼執行將保持暫停狀態,直到調用 generator 的 next() 方法爲止。每次調用 generator 的 next() 方法時,generator 都會恢復執行並返回 iterator 結果。es6

嗯……理論先到這裏,讓咱們看一個例子:github

function* UUIDGenerator() {
    let d, r;
    while(true) {
        yield 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
            r = (new Date().getTime() + Math.random()*16)%16 | 0;
            d = Math.floor(d/16);
            return (c=='x' ? r : (r&0x3|0x8)).toString(16);
        });
    }
};
複製代碼

UUIDGenerator 是一個 generator 函數,它使用當前時間和隨機數計算 UUID ,並在每次執行時返回一個新的 UUID 。redux

要運行上面的函數,咱們須要建立一個能夠調用 next() 的 generator 對象:

const UUID = UUIDGenerator();
// UUID is our generator object

UUID.next() 
// return {value: 'e35834ae-8694-4e16-8352-6d2368b3ccbf', done: false}
複製代碼

每次 UUID.next() 返回值的 value 值是新的 UUID ,done 值將始終爲 false ,由於咱們處於一個無限循環中。

注意:咱們在無限循環上暫停,這是一種很酷的方式。在 generator 函數中的任何「中止點」處,不只能夠爲外部函數生成值,還能夠從外部接收值。

有許多 generator 的實現,而且不少庫都在大量使用。好比說 cokoaredux-saga


Async/Await (ES7)

依照慣例,當一個異步操做返回由 Promise 處理的數據時,回調會被傳遞並調用。

Async/Await 是一種特殊的語法,以更溫馨的方式使用 Promise,這種方式很是容易理解和使用。

Async 關鍵字用於定義異步函數 ,該函數返回一個 AsyncFunction 對象。

Await 關鍵字用於暫停異步函數執行,直到 Promise 被解決(resolved 或者 rejected),並在完成後繼續執行 async 函數。恢復時,await 表達式的值是已執行的 Promise 的值。

關鍵點:

  1. Await 只能在異步函數中使用。
  2. 具備 async 關鍵字的函數將始終返回 promise。
  3. 在相同函數下的多個 await 語句將始終按順序運行。
  4. 若是 promise 正常被 resolve,則 await 會返回 promise 結果。可是若是被 reject,它就會拋出錯誤,就像在那行有 throw 語句同樣。
  5. 異步函數不能同時等待多個 promise。
  6. 若是在 await 以後使用 await 屢次,而且後一條語句不依賴於前一條語句,則可能會出現性能問題。

到目前爲止一切順利,如今讓咱們看一個簡單的例子:

async function asyncFunction() {

  const promise = new Promise((resolve, reject) => {
    setTimeout(() => resolve("i am resolved!"), 1000)
  });

  const result = await promise; 
  // wait till the promise resolves (*)

  console.log(result); // "i am resolved!"
}

asyncFunction();
複製代碼

await promise 這一行,asyncFunction 執行「暫停」,並在 promise 被解決後回覆,result(第 95 行的 const result)變成它的結果。上面的代碼在一秒鐘後展現 「i am resolved!」。


Generator 和 Async-await 比較

  1. Generator 函數/yieldAsync 函數/await 均可以用來編寫「等待」的異步代碼,這意味着代碼看起來像是同步的,即便它確實是異步的。
  2. Generator 函數按照 yield 接着 yield 的順序執行,就是說一個 yield 表達式經過迭代器來執行一次(執行 next 方法),而 Async-await 按照 await 接着 await 的順序依序執行。
  3. Async/await 能夠更容易地實現 Generators 的特定用例。
  4. Generator 的返回值始終是 {value: X, done: Boolean}。對於 Async 函數它將始終是一個將解析爲值 X 或拋出錯誤的 promise
  5. Async 函數能夠分解爲 Generator 和 promise 來實現,這些都頗有用。

若是您想要添加到個人電子郵件列表中,請考慮 在此處輸入您的電子郵件,並在 medium 上關注我以閱讀更多有關 javascript 的文章,並在 github 上查看個人瘋狂代碼。若是有什麼不清楚的,或者你想指出什麼,請在下面評論。

你可能也喜歡個人其餘文章:

  1. Nodejs app structure
  2. Javascript data structure with map, reduce, filter
  3. Javascript- Currying VS Partial Application
  4. Javascript ES6 — Iterables and Iterators
  5. Javascript performance test — for vs for each vs (map, reduce, filter, find).
  6. Javascript — Proxy

若是你喜歡這篇文章,請鼓掌。提示:你能夠拍 50 次!此外,歡迎推薦和分享,以幫助其餘人找到它!

謝謝!

若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。


掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章
相關標籤/搜索