前言:每一个特性的出现,总有它的用途,而只有用了,才能更好地理解它。不管是Generator,还是Async +Await,还有Promise都是为了解决异步而存在;存在及合理;这些知识是自己整理得来的,一边学习,一边加深印象巩固,可能不是那样完美,也有缺漏,欢迎补充;这些内容可能在项目中用不上,但是也可以了解很多概念性的知识;像我之前都没听过Generator,但是在学Async +Await的时候,还是先了解Generator比较好;
写这个文章之前也写了Promise,同步异步 的一些知识,不懂的可以过去看看,欢迎补充完善
【JavaScript 】运行机制详解 同步 异步 Event Loop
【ES6 】Promise 在 ES6 中的基本应用
接下来我们进入正题:
什么是Generator?
- 语法上,可以把理解成,Generator 函数是一个状态机,封装了多个内部状态。(但是这丫的不是函数,切记)
- 形式上,Generator 函数是一个普通函数。
整个Generator函数就是一个封装
的异步任务,或者说是异步任务
的容器,异步操作需要暂停的地方,都用yield
语句。
Generator 函数的语法
function *G() {
yield 100
}
const g = G()
console.log( g.next() ) // {value: 100, done: false}
yield 和 next 关键字
先看一段代码
function *G() {
const a = yield 100
const b = yield 200
const c = yield 300
}
const g = G()
console.log(g.next()) // value: 100, done: false
console.log(g.next()) // value: 200, done: false
console.log(g.next()) // value: 300, done: false
console.log(g.next()) // value: undefined, done: true
先简单分析一下代码
- 定义Generator时,需要使用function*,其他的和定义函数一样。内部使用yield
- 执行G()之后,G内部的代码不会立即执行,而是出于一个
暂停状态
- 执行第一个g.next()时,会
激活
刚才的暂停状态,开始执行g内部的语句,但是,直到遇到yield
语句。一旦遇到yield语句时,它就会将yield后面的表达式执行,并返回执行的结果,然后又立即进入暂停状态
。 - 因此第一个console.log(g.next())打印出来的是{ value: 100, done: false },
value
是第一个yield
返回的值,done: false
表示目前处于暂停状态,尚未执行结束,还可以再继续往下执行。 - 执行第二个g.next()和第一个一样,不在赘述。此时会执行完第二个yield后面的表达式并返回结果,然后再次进入
暂停状态
- 执行第三个g.next()时,程序会打破暂停状态,继续往下执行,但是遇到的不是
yield
而是return
。这就预示着,即将执行结束了。因此最后返回的是{ value: 300, done: true },done: true
表示执行结束,无法再继续往下执行了。 - 再去执行第四次g.next()时,就只能得到
{ value: undefined, done: true }
,因为已经结束,没有返回值了 - 就算再进行第五次g.next(),也只能得到第四次的返回结果
yield
通过如上代码示例可得出:
- g()不会立即出发执行,而是一上来就
暂停
yield
具有数据返回功能, yield后面的数据会被返回,返回的数据存放在value
数据中- 遇到
yield
时,会执行yeild后面的表达式,并返回执行之后的值,然后再次进入暂停状态,此时done: false - 遇到
return
时,会返回值,执行结束,即done: true; - 每次g.next()的返回值永远都是
{value: ... , done: ...}
的形式
next
向yield
传递
Generator最终如何处理异步操作
先来一段Promise的操作,做一下对比
//今天先写到这里 有时间接着补充
async 函数是什么?
从最早的回调函数,到promise,再到Generator,每次都有改进,但也有一些不彻底,一直在进步,改进怎么样才能更优雅的解决异步,于是asyne出现了;
async
就是Generator
函数的语法糖,使用,
关键字 async
来表示,在函数内部使用 await
来表示异步。
它有以下几个特点:
- 建立在 promise 之上。所以,不能把它和回调函数搭配使用。但它会声明一个异步函数,并隐式地返回一个Promise。因此可以直接return变量,无需使用 Promise.resolve 进行转换。
- 和 promise 一样,是非阻塞的。但不用写 then 及其回调函数,这减少代码行数,也避免了代码嵌套。而且,所有异步调用,可以写在同一个代码块中,无需定义多余的中间变量。
- 它的最大价值在于,可以使异步代码,在形式上,更接近于同步代码。
- 它总是与 await 一起使用的。并且,await 只能在 async 函数体内。
- await 是个运算符,用于组成表达式,它会阻塞后面的代码。如果等到的是 Promise 对象,则得到其 resolve 值。否则,会得到一个表达式的运算结果。