- 原文地址:Javascript - Generator-Yield/Next & Async-Await
- 原文作者:Deepak Gupta
- 譯文出自:掘金翻譯計劃
- 本文永久連結:github.com/xitu/gold-m…
- 譯者:iceytea
- 校對者:huimingwu, zsky
Generator (ES6)
generator 函式是一個可以根據使用者需求,在不同的時間間隔返回多個值,並能管理其內部狀態的函式。如果一個函式使用了 function* 語法,那麼它就變成了一個 generator 函式。
它們與正常函式不同,正常函式在單次執行中完成執行,而 generator 函式可以被暫停和恢復。它們確實會執行完成,但觸發器在我們手中。它們使得對非同步函式能有更好的執行控制,但這並不意味著它們不能用作同步函式。
注意:執行 generator 函式時,會返回一個新的 Generator 物件。
generator 的暫停和恢復是使用 yield
和 next
完成的。讓我們來看看它們是什麼,以及它們能做什麼。
Yield/Next
yield
關鍵字暫停 generator 函式的執行,並且yield
關鍵字後面的表示式的值將返回給 generator 的呼叫者。它可以被理解為基於 generator 版本的return
關鍵字。
yield
關鍵字實際上返回一個具有 value
和 done
兩個屬性的 IteratorResult
物件。(如果你不瞭解什麼是 iterators 和 iterables,點選這裡閱讀)。
一旦暫停
yield
表示式,generator 的程式碼執行將保持暫停狀態,直到呼叫 generator 的next()
方法為止。每次呼叫 generator 的next()
方法時,generator 都會恢復執行並返回 iterator 結果。
嗯……理論先到這裡,讓我們看一個例子:
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 。
要執行上面的函式,我們需要建立一個可以呼叫 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 的實現,並且很多庫都在大量使用。比如說 co、koa 和 redux-saga。
Async/Await (ES7)
依照慣例,當一個非同步操作返回由 Promise
處理的資料時,回撥會被傳遞並呼叫。
Async/Await 是一種特殊的語法,以更舒適的方式使用 Promise,這種方式非常容易理解和使用。
Async 關鍵字用於定義非同步函式 ,該函式返回一個 AsyncFunction 物件。
Await 關鍵字用於暫停非同步函式執行,直到 Promise
被解決(resolved 或者 rejected),並在完成後繼續執行 async
函式。恢復時,await 表示式的值是已執行的 Promise 的值。
關鍵點:
- Await 只能在非同步函式中使用。
- 具有 async 關鍵字的函式將始終返回 promise。
- 在相同函式下的多個 await 語句將始終按順序執行。
- 如果 promise 正常被 resolve,則
await
會返回promise
結果。但是如果被 reject,它就會丟擲錯誤,就像在那行有throw
語句一樣。- 非同步函式不能同時等待多個 promise。
- 如果在 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 比較
- Generator 函式/yield 和 Async 函式/await 都可以用來編寫“等待”的非同步程式碼,這意味著程式碼看起來像是同步的,即使它確實是非同步的。
- Generator 函式按照 yield 接著 yield 的順序執行,就是說一個 yield 表示式通過迭代器來執行一次(執行
next
方法),而 Async-await 按照 await 接著 await 的順序依序執行。 - Async/await 可以更容易地實現 Generators 的特定用例。
- Generator 的返回值始終是 {value: X, done: Boolean}。對於 Async 函式它將始終是一個將解析為值 X 或丟擲錯誤的 promise。
- Async 函式可以分解為 Generator 和 promise 來實現,這些都很有用。
如果您想要新增到我的電子郵件列表中,請考慮 在此處輸入您的電子郵件,並在 medium 上關注我以閱讀更多有關 javascript 的文章,並在 github 上檢視我的瘋狂程式碼。如果有什麼不清楚的,或者你想指出什麼,請在下面評論。
你可能也喜歡我的其他文章:
- Nodejs app structure
- Javascript data structure with map, reduce, filter
- Javascript- Currying VS Partial Application
- Javascript ES6 — Iterables and Iterators
- Javascript performance test — for vs for each vs (map, reduce, filter, find).
- Javascript — Proxy
如果你喜歡這篇文章,請鼓掌。提示:你可以拍 50 次!此外,歡迎推薦和分享,以幫助其他人找到它!
謝謝!
如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可獲得相應獎勵積分。文章開頭的 本文永久連結 即為本文在 GitHub 上的 MarkDown 連結。
掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。