1、简述async函数
答:这个函数的作用是为了让异步编程更加简单。
他是Generator函数的语法糖。
const fs = require('fs')
const readFile = function(fileName){
return new Promise((resolve, reject) => {
fs.readFile(fileName, function(err, data){
if(err) return reject(err)
resolve(data)
})
})
}
const gen = function*(){
const f1 = yield readFile('/file1')
const f2 = yield readFile('/file2')
console.log(f1.toString())
console.log(f2.toString())
}
用async函数简写
const asyncFun = async function(){
const f1 = await readFile('/file1')
const f1 = await readFile('/file1')
console.log(f1.toString())
console.log(f2.toString())
}
2、async函数对Generator函数有哪些改进
答:① 内置执行器。Generator函数的执行必须依靠执行器,而async函数自带执行器
② 更好的语义。async和await比起星号和yield,语义更加清楚。async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果
③ 更广的实用性。Generator函数的co模块规定,yield命令后面只能是Thunk函数或者Promise对象,而async函数的await命令后面,可以是Promise对象和原始类型的值(会自动转Promise对象)
④ 返回值是Promise。Generator函数返回的是Iterator对象,async返回的是Promise对象
⑤ async函数是多个异步操作包成一个Promise对象,await命令就是内部then的语法糖
3、async的基本用法
答:① async函数返回一个Promise对象,可以使用then方法添加回调函数。
② async函数一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体后面的语句。
③ async 函数内部的return命令返回值,会被then方法回调函数接受到。
④ async函数内部抛出错误,会导致返回的Promise对象变为reject状态,抛出的错误对象被catch方法回调函数接收到
⑤ async函数可以保留运行栈
async function fun(){
const fun1 = await fun1()
const fun2 = await fun2()
await new Promise((resolve, reject)=>{resolve(111)})
return fun2
}
fun().then(res => {console.log(res)}).catch(err => {console.log(err)})
async function fun1(){throw new Error('error')}
fun1().then(res => console.log(res), err => console.log(err)) // reject Error: error
const a = async () => {
await b()
c()
} // b()运行得到时候,a()是暂停执行的,上下文环境保存着,一旦b()或者c()报错,错误栈堆将包括a()
4、async函数的有哪些使用形式
答:① 函数声明
② 函数表达式
③ 对象的方法
④ Class方法
⑤ 箭头函数
// ① 函数声明
async function fun(){}
fun().then()
// ② 函数表达式
const fun = async function(){}
fun().then()
// ③ 对象的方法
let obj = {async fun(){}}
obj.fun().then()
// ④ Class方法
class Fun{
constructor(){
this.a = 111
}
async fun(){
return this.a
}
}
cont f = new Fun()
f.fun().then()
// ⑤ 箭头函数
const fun = async () => {}
fun().then()
5、async函数返回的Promise对象的状态变化是什么样的
答:async函数返回的Promise对象,必须要等到内部的所有await命令后面的Promise对象执行完,才会状态的变化,除非遇到return语句或者抛出错误。即,async函数内部的异步操作执行完,才会执行then方法指定的回调函数。
async function fun(){
const fun1 = await fun1()
const fun2 = await fun2()
await new Promise((resolve, reject)=>{resolve(111)})
return fun2
}
// 只有当fun函数内部的所有异步操作完成,才会执行then回调函数
fun().then(res => {console.log(res)})
6、简述await命令
答:① 其后面跟着一个Promise对象,返回Promise对象的结果
② 如果不是Promise对象,就直接返回对应的值就行
③ 如果后面跟着thenable对象(即定义了then方法的对象),await会将其等同于Promise对象
④ await命令后面的Promise对象如果变为reject状态,那么reject参数会被catch回调函数接收到
⑤ async函数中任何一个await语句后面的Promise对象变为reject状态,那么整个async函数将会中断执行,如果不希望中断,可以使用try…catch语句或者await后面的Promise对象再跟着一个catch方法来处理这个错误
async function fun(){
return await 123 // 等同于 return 123。可以在await加return,也可以不加,效果是一样的
}
fun().then(res => console.log(res)) // 123
async function fun1(){
await Promise.reject('error')
await Promise.resolve(1111) // 这句不会执行,因为上面await语句将async变为reject状态
}
fun1().then().catch(err => console.log(err)) // 'error'
async function fun2(){
try{
await Promise.reject('error')
}catch(err){}
// 上面try..catch方法处理可以用下面的方式进行替代
// await Promise.reject('error').catch(err => console.log(err))
await Promise.resolve(1) // 这句会执行
}
fun2().then(res => console.log(res)).catch(err => console.log(err)) // 1
7、使用async函数的注意点
答:① 里面的await命令后的Promise对象运行结果可能是rejected,所以最好把await命令放在try…catch中或者Promisee对象后面跟着catch回调捕捉错误
② await命令只能用在async函数中,用在普通函数中会报错
② 多个await操作如果没有先后关系,可以使用Promise.all()一起执行
let [p1, p2] = await Promise.all([p1(), p2()])
或者
let p1Promise = p1(), p2Promise = p2()
let p1 = await p1Promise, p2 = await p2Promise
8、async函数的实现原理
答:就是将Generator函数和自动执行器,包装在一个函数里
async function fun(){}
// 等同于
function fun(){
return spawn(function *(){}) // spawn是自动执行器
}
9、async函数、Promise、Generator函数比较
答:都可以解决回调地狱问题,可以使得异步操作更简单
① Promise比ES5中的回调要简单,但代码看上去都是Promise的API,语义性不强
② Generator函数必须要一个自动执行器来返回一个Promise对象,而且必须要保证yield语句后面的表达式返回一个Promise对象
③ async函数语义化强且带有自动执行器,代码量少,内部语法不需要暴露给用户