这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战
背景
最近刚上手用 TypeScript,然后时不时会见到“奇奇怪怪的报错”。比如说今天这个:
这是啥子情况?我返回的不是个对象吗,promise 是怎么回事。难道因为是 async?瞎蒙着给 getCategoryTree 调用的地方加了 await,就不会报错了!果然是 async 搞的鬼。
emmm.. 看来对 async/await 的认知还不到位,得再认识认识 ——
async 函数
async 函数的返回值
async函数一定会返回一个promise对象。如果 async 函数显示指定的返回值不是一个 promise ,那么这个返回值将会被隐式地包装在一个 promise 中被 resolve;对于异常或错误的情况,则会通过async函数中抛出 reject。
resolve 的情况:
async function foo() {
return 1
}
// 等价于:
function foo() {
return Promise.resolve(1)
}
// Promise {<fulfilled>: 'hello'}
reject 的情况:
async function bar(){
throw new Error('sth error');
}
// 等价
async function bar(){
return Promise.reject(new Error('sth error'))
}
// Promise {<rejected>: Error: sth error
await
async 函数可能包含0个或者多个 await 表达式。如果 async 函数内没有 await 表达式,则函数体都是同步运行的。如果有多个 await,async 会等待所有 await 的 promise 执行完毕才会发生状态改变。
await 表达式会中断函数体的执行,直到等待的 promise 异步操作完成后才恢复进程。
await 关键字只在 async 函数内有效。
async/await 的实战场景
- B 请求依赖于 A 请求的返回结果(异步、依次执行)
const d1 = async ()=>{
const res_a = await requestA()
const res_b = await requestB(res_a)
console.log(resB)
}
- C 请求依赖于 A、B 请求的返回(A、B同步执行,C随后执行)
const requestA = async ()=>{}
const requestB = async ()=>{}
const d2 = async ()=>{
const [res_a, res_b] = await Promise.all([ requestA(), requestB() ])
const res_c = await requestC(res_a, res_b)
console.log(res_c)
}
Generator 函数
async/await 和 Generator 的渊源
async 函数就是 Generator 函数的语法糖
async 对 Generator 函数的改进:
- 内置执行器,调用函数后自动执行,不需要通过
.next()进行下一步操作。 - 返回
Promise。从上文可知,async函数最终会返回一个Pormise对象,这使我们可以方便的用.then()进行链式操作,也可以继续作为await的参数进行同步操作。
Generator 函数基本特性和使用
- 定义
Generator函数只需要比普通函数多个*号; - 调用一个生成器函数不会马上执行里面的语句,而是返回一个迭代器对象。
- 直到手动调用迭代器的
next方法,函数体内的语句才会开始执行,并到第一个出现的yield位置为止。 yield关键字向外部返回一个值,这个值在 next 方法返回对象中拿到。yield关键字不会结束函数的执行,只是暂停执行,直到外部下一次调用next方法,生成器函数继续执行。- 在调用生成器的
next方法时可以传递一个参数,所传入的参数将会作为yield语句的返回值 - 另外,生成器函数的
throw方法可以抛出一个异常。
function * gen(){
console.log('--- start ---');
const res = yield 'foo'
console.log(res) // bar
}
const iterator = gen() //此时并不会马上执行函数体内的语句,而是返回一个迭代器对象
const res = iterator.next() //函数开始执行,直至碰到第一个 yield 关键字,暂停。
console.log(res) // {value:'foo', done:false}。next 方法返回一个对象 `{value, done}` 。value 指 yield 关键字后跟着的返回值(此处为 'foo'),done 表示是否生成器是否已全部执行完毕。
iterator.next('bar') //next 传递的参数,将作为 yield 语句的返回值
参考链接
async 函数的含义和用法(阮一峰)
async 函数(MDN)
7张图,20分钟就能搞定的async/await原理!(林三心)
Generator 函数(MDN)