JavaScript - Generator-Yield/Next & Async-Await
2019年03月16日 译者:highya
Generator (ES6)
generator 函数是一个可以根据用户需求在不同时间间隔返回多个值,并能管理其内部状态的函数。如果一个函数使用
Function*
语法,则该函数就变成了一个 generator 函数。
与普通函数不同,普通函数在单次执行中完成运行,而 generator 函数运行过程中可以被暂停和恢复。它们能运行完成,但是触发器在我们手中。这使得对异步函数有更好的执行控制,但也并不意味它们不能用作同步函数。
注意:执行 generator 函数时会返回一个新的 Generator 对象。
generator 函数的暂停和恢复分别通过 yield
& next
实现。让我们来看一下它们是什么以及能做什么。
Yield / Next
yield
关键字暂停 generator 函数执行,并且它后面表达式的值将返回给 generator 调用者。它也可以被理解成基于 generator 版本的return
关键字。
yield
关键字实际上返回一个具有 value
和 done
两个属性的 IteratorResult
对象。(如果你不明白 iterators 和 iterables,请点击这里)。
一旦暂停
yield
表达式,generator 代码执行将保持暂停状态,直到调用 generator 的next()
。每次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()
都将返回一个新的 UUID 值,done 始终为 false, 因为我们处于一个无限循环中。
注意:我们在无限循环中暂停是非常酷的,而且在 generator 函数中任何“停止点”,不仅可以为外部函数生成值,还可以从外部函数接收值。
有很多 generator 的实现,很多库都有大量的使用,比如 co,koa,redux-saga。
Async/Await (ES7)
依照惯例,当一个异步操作返回由 Promise
处理的数据时,回调会被传递并调用。
Async/Await 是一种特殊的语法,以更舒适的方式使用 promise,这种方式非常容易理解和使用。
Async 关键字用于定义异步函数,该函数返回一个 AsyncFunction
对象。
Await 关键字用于暂停异步函数执行,直到 Promise
完成(resolved 或者 rejected),并在之后继续执行异步函数。当恢复时,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
为它的返回结果。代码执行结果:在一秒钟后输出 “i am resolved!
”。
Generator 与 Async-await 比较
-
Generator 函数/yield 和 Async 函数/await 都可以用来编写“等待”的异步代码,这意味着代码形似同步,实际却是异步的。
-
Generator 函数按照 yield 顺序执行,即一个 yield 表达式通过它的迭代器执行一次(
next
方法)。而 Async 函数则是按照 await 顺序执行。 -
Async/await 可以更容易地实现 Generators 的特定用例。
-
Generator 的返回值始终是 { value: X, done: Boolean }。而 Async 函数返回值是一个 X 或抛出错误的 promise。
-
Async 函数可以分解为 Generator 和 promise 来实现。
如果您想要添加到我的电子邮件列表中,请考虑 在此处输入您的电子邮件,并在 medium 上关注我以阅读更多有关 javascript 的文章,并在 github 上查看我的代码。如果有什么疑问或者指正,请在下面评论。
您可能还喜欢我的这些文章:
如果你喜欢这篇文章,请鼓掌。友情提示:您可以拍50次!此外,请记得推荐和分享,以帮助其他人找到它!
谢谢!
FENews 是由一群热爱技术的前端小伙伴自发组成的团队。团队会定期创作和翻译前端相关的技术文章,同时我们也欢迎外部投稿或加入我们的核心编辑团队。如果您对我们感兴趣,请关注我们的公众号: