[译] 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前端后端区块链产品设计人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划官方微博知乎专栏

相关文章
相关标签/搜索