async-await- generator

原理

async函数是对generator函数和自动执行器做了一层封装,返回一个promise。因为generator函数会返回1个迭代器对象,循环调用这个遍历器对象的next方法,上一个next的value作为下一个next函数的参数传入,如果next返回值done是true说明已经遍历完,最终返回1个promise。

async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await, 是语法糖
进一步说,async函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而await命令就是内部then命令的语法糖。

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
// ruanyifeng 版本
function spawn(genF){
return new Promise(resolve, reject){
const gen = genF() // 遍历器对象

function step(nextFn){
let next
try{
next = nextFn()
}catch(e){
return reject(e)
}

if(next.done){
return resolve(next.value)
}

Promise.resolve(next.value)
.then(
(v)=>{function(){step( function(){return gen.next(v)} }},
(e)=>{function(){ step( function(){return gen.throw(e)} )}}
)

}
step(function(){return gen.next(undefined)}) // 这个函数被调用是执行迭代器的next方法

}
}
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
46
47
48
49
// 个人版本
// 有genrator 函数写法,引入上方spawn 函数
function fn(args) {
return spawn(function* () {
console.log(1)
let res1 = yield Promise.resolve(2)
console.log(res1)
let res2= yield Promise.resolve(3)
console.log(res2)
return 3
});
}

// async写法
async function fn(args) {
console.log(1)
let res1 = await Promise.resolve(2)
console.log(res1)
let res2 = await Promise.resolve(3)
console.log(res2)
return 3
}

function spawn(genF){
return new Promise((resolve, reject)=>{
var iterator = genF()

function step(fn){
let res
try{
res = fn()

}catch(e){
reject(e)
}

if(res.done){
resolve(res.value)
}else{
Promise.resolve(res.value).then(
value => {step(()=>{return iterator.next(value)})},
err => {step(()=>{return iterator.throw(err)})}
)
}
}

step(()=>{return iterator.next(undefined)})// 这个函数被调用是执行迭代器的next方法
})
}

关于genetator 函数

next()、throw()、return()这三个方法本质上是同一件事,可以放在一起理解。它们的作用都是让 Generator 函数恢复执行,并且使用不同的语句替换yield表达式

  • next()是将yield表达式替换成一个值。
    next方法可以带一个参数,该参数就会被当作上一个yield表达式的返回值。
  • throw()是将yield表达式替换成一个throw语句
    Generator 函数 返回的遍历器对象,都有一个throw方法,可以在函数体外抛出错误,然后在 Generator 函数体内捕获
  • return()是将yield表达式替换成一个return语句
    Generator 函数 返回的遍历器对象,还有一个return方法,可以返回给定的值,并且终结遍历 Generator 函数。

注意点

  1. await只能用在async中,否则报错
  2. await等待的promise如果被reject, 异常会被抛出,需加try..catch
  3. 异步操作不存在依赖的情况下,同时触发异步,减少不必要等待时间

语法

[return_value] = await expression
表达式
一个 Promise 对象或者任何要等待的值。
返回值
返回 Promise 对象的处理结果。如果等待的不是 Promise 对象,则返回该值本身。


demo

await返回值

await会暂停当前 async function 的执行,等待promise处理完成,将promise resolve的结果作为返回值,如果promise异常,则抛出异常(区别于promise内部错误不反应到外部,只能通过catch捕获),如果不是promise是个普通值,则直接返回普通值

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
async function f1(){
try{
var p1 = await Promise.reject(100)
}catch(e){
console.log(e)
}
}
f1()
// 100

Promise.reject(100).catch(e=>{
console.log(e)
})
// 100
```

## await 让出线程
遇到await 会让出线程,跳出async函数,执行完同步代码,再跳回async函数内部

```javascript
async function test(){
let p1 = await 1
console.log('p1 is ',p1)
let p2 = await new Promise((resolve, reject)=>{resolve('123')})
console.log('p2 is ',p2)
return 1000
}

var result = test()
console.log('result is', result)

result.then((x)=>{console.log('I am resolved! Value is :',x)})


// 打印顺序
// result is Promise {<pending>}__proto__: Promise[[PromiseStatus]]: "resolved"[[PromiseValue]]: 1000
// p1 is 1
// p2 is 123
// I am resolved! Value is : 1000

async函数会返回promise(例子见上)

当调用一个 async 函数时,会返回一个 Promise 对象。当这个 async 函数返回一个值时,Promise 的 resolve 方法会负责传递这个值;当 async 函数抛出异常时,Promise 的 reject 方法也会传递这个异常值。

当不存在异步依赖关系

同时触发异步,减少不必要等待时间

1
2
3
4
5
6
7
8
// 写法一
let [foo, bar] = await Promise.all([getFoo(), getBar()]);

// 写法二
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;