概述
async function(异步函数)是由Brian Terlson 提议的 ECMAScript 2017 新特性,表示一个函数内部有异步操作,实际可以说是生成器函数function* ()的语法糖,async具有自执行器。
声明方式
async function asyncfunction(){
//函数体内容
}
let func = async function(){
//函数体内容
}
...
返回值
async function 总是返回promise对象,这个promise对象只有在内部的所有await语句处理完成之后,其状态才会发生变化
来说说await
- await只能在async函数内部使用,表示这个部分有需要等待的操作。
- await后面可以跟一个函数(普通函数或者async函数都可以)、表达式或者值。如果这些表达式或者函数并不产生或返回一个promise对象的话,await将这些值转换为一个立即resolve的promise对象。
- 当执行async函数遇到await的时候,return语句会马上执行,async立即返回一个promise对象,这个promise的resolved值是return返回的值,并在await所在处的异步操作完成之后再接着执行async函数内部剩下的语句(
中断时把函数体中剩下的语句丢到微任务等待队列中
)。 - 只要一个await后面的promise对象出现了reject,那么整个async函数便会中断执行。如果要制止出现这种情况,可以这样做:
// 1.用try和catch语句包裹住可能出错的await语句
async function f() {
try {
await Promise.reject('出错了');
} catch(e) {
}
return await Promise.resolve('hello world');
}
f().then(v => console.log(v))// hello world
//2.在await的表达式后面用catch()进行异常的捕捉。
async function f() {
await Promise.reject('出错了').catch(err=>console.log(err));
return await Promise.resolve('hello world');
}
f().then(v => console.log(v))// 输出“出错了”和“hello world”
说说上面的红字部分
这个理解了比较长的时间,因为一道考察event loop的面试题
async function a1 () {
console.log('a1 start')
await a2()
console.log('a1 end')
}
async function a2 () {
console.log('a2')
}
console.log('script start')
setTimeout(() => {
console.log('setTimeout')
}, 0)
Promise.resolve().then(() => {
console.log('promise1')
})
a1()
let promise2 = new Promise((resolve) => {
resolve('promise2.then')
console.log('promise2')
})
promise2.then((res) => {
console.log(res)
Promise.resolve().then(() => {
console.log('promise3')
})
})
console.log('script end')
//正确的输出应该是:
script start
a1 start
a2
promise2
script end
promise1
a1 end
promise2.then
promise3
setTimeout
但是,关于为什么a1 end出现在promise1的后面我想了好久(大佬勿喷)。
然后经过几次尝试吧,我发现async遇到await之后,会把函数体中剩下的代码丢到微任务队列里面。然后我就解决了我的疑问。
分析一下上面的代码:
首先,主程序(第一个宏任务)执行,执行下列操作
- 输出script start
- 宏任务队列置入一个setTimeout
- 主程序中的微任务队列中置入一个微任务(console.log("promise1")
- 输出a1 start
- 立即resolve
- 把a1中剩下的语句置入主程序的微任务等待队列
- 输出a2
- 执行new Promise操作,输出promise2
- 主程序中的微任务队列中置入一个微任务(console.log(res))
- 输出script end
- 主程序执行完毕。开始执行微任务队列。
微任务队列执行:
- 输出promise1
- 输出a1 end
- 输出promise2.then
- 主程序的微任务等待队列中置入一个微任务(console.log("promise3"))
- 输出promise3
主程序的微任务队列执行完毕,执行下一个宏任务
输出setTimeout
程序执行完毕。
另外可以试着分析一下下面的代码的输出结果:
async function a1 () {
console.log('a1 start')
await a2();
let i=18
console.log(i)
console.log('a1 end')
await a3();
console.log("aftera3");
return new Promise((resolve,reject)=>{
resolve("78");
})
}
function a2 () {
console.log('a2')
}
function a3 () {
console.log('a4');
Promise.resolve().then(()=>{
console.log("hehe1");
});
}
console.log('script start')
Promise.resolve().then(() => {
console.log('promise1')
})
Promise.resolve().then(() => {
console.log("extra message 1");
console.log("extra message 2");
})
Promise.resolve().then(() => {
console.log("extra message 3");
console.log("extra message 4");
})
Promise.resolve().then(() => {
console.log("extra message 5");
console.log("extra message 6");
})
a1()
正确输出是:
script start
a1 start
a2
promise1
extra message 1
extra message 2
extra message 3
extra message 4
extra message 5
extra message 6
18
a1 end
a4
hehe1
aftera3
网友评论