[译] Javascript - Generator-Yield/Next 和 Async-Await

Generator (ES6)

generator 函数是一个可以根据用户需求,在不同的时间间隔返回多个值,并能管理其内部状态的函数。如果一个函数使用了 function* 语法,那么它就变成了一个 generator 函数。

它们与正常函数不同,正常函数在单次执行中完成运行,而 generator 函数可以被暂停和恢复。它们确实会运行完成,但触发器在我们手中。它们使得对异步函数能有更好的执行控制,但这并不意味着它们不能用作同步函数。

注意:执行 generator 函数时,会返回一个新的 Generator 对象。

generator 的暂停和恢复是使用 yieldnext 完成的。让我们来看看它们是什么,以及它们能做什么。

Yield/Next

yield 关键字暂停 generator 函数的执行,并且 yield 关键字后面的表达式的值将返回给 generator 的调用者。它可以被理解为基于 generator 版本的 return 关键字。

yield 关键字实际上返回一个具有 valuedone 两个属性的 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 的实现,并且很多库都在大量使用。比如说 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前端后端区块链产品设计人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划官方微博知乎专栏

猜你喜欢

转载自juejin.im/post/5c7ca6d95188256ec63f289c