Generator函数及Async/Await

1.Generator函数

Generator函数是ES6中提供的一种异步编程解决方法。Generator是一个状态机,可以依次遍历函数内部的没一个状态。简单可以理解为一个可暂停执行的函数,yield就是暂停标志。

  • function后面有”*”
  • 函数内部有yield表达式
1
2
3
4
5
6
functon * call(){
console.log(1)
yield '1'
consol.log(2)
yield '2'
}

2.Generator函数执行机制

使用generator函数和使用普通函数一样,在后面加上()就可以了,但是函数并不会马上执行,而是返回一个指向内部函数的指针,调用遍历器对象Iterator的next方法,会分步执行generator函数中的对应逻辑

1
2
3
4
5
6
7
8
9
let f = call
f.next()
//console => 1
//yield => {value: '1', done: false}
f.next()
//console => 2
//yield => {value: '2', done: false}
f.next()
//yield => {value: undefined, done: true}

3.next方法

next函数不传入参数时yield表达式返回值是undefined,当next传入参数的时候参数会作为上一步yield的返回值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
functon * call2(){
console.log('开始')
const a = yield 1
consol.log(a)
const b = yield 2
console.log(b)
}

const f2 = call2()

f2.next()
//console => '开始'
f2.next(10)
//console => (10)
//yield => {value: 1, done: false}
f2.next(20)
//console => (20)
//yield => {value: 2, done: false}
f2.next()
//yield => {value: undefined, done: true}

4.return方法

return返回给定值并结束遍历Generator函数。return有参数返回参数没参数返回undefined。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
functon * call3(){
console.log('开始')
const a = yield 1
consol.log(a)
const b = yield 2
console.log(b)
}

const f3 = call3()

f3.next()
//console => '开始'
f3.next(10)
//console => (10)
//yield => {value: 1, done: false}
f3.return("end")
//yield => {value: "end", done: true}
f3.next()
//yield => {value: undefined, done: true}

5.*yield

*yield表示yield返回另一个Generator对象,可以在Generator内部调用另一个Generator函数。

1
2
3
4
5
6
7
8
9
10
11
12
function* callA() {
console.log("callA: " + (yield))
}
function* callerB() {
while (true) {
yield* callA();
}
}
const callerObj = callerB()
callerObj.next()
callerObj.next("first") // console => callA :first
callerObj.next("second") // console => callA :second

6.async/await

ES7中引入,可以理解为Generator的语法糖,对Generator函数进行了修改。await等待的是一个隐式返回Promise作为结果的函数。async、await等同于一个generator+自动执行器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
function fn(nums) {
return new Promise(resolve => {
setTimeout(() => {
resolve(nums * 2)
}, 1000)
})
}
function* gen() {
const num1 = yield fn(1)
console.log(num1) // 2
const num2 = yield fn(num1)
console.log(num2) // 4
const num3 = yield fn(num2)
console.log(num3) // 8
return num3
}
function generatorToAsync(generatorFn) {
return function() {
const gen = generatorFn.apply(this, arguments) // gen有可能传参
// 返回一个Promise
return new Promise((resolve, reject) => {
function go(key, arg) {
let res
try {
res = gen[key](arg) // 这里有可能会执行返回reject状态的Promise
} catch (error) {
return reject(error) // 报错的话会走catch,直接reject
}
// 解构获得value和done
const { value, done } = res
if (done) {
// 如果done为true,说明走完了,进行resolve(value)
return resolve(value)
} else {
// 如果done为false,说明没走完,还得继续走
// value有可能是:常量,Promise,Promise有可能是成功或者失败
return Promise.resolve(value).then(val => go('next', val), err => go('throw', err))
}
}
go("next") // 第一次执行
})
}
}
const asyncFn = generatorToAsync(gen)
asyncFn().then(res => console.log(res))