前言
async 函数是使用async关键字声明的函数。 async 函数是AsyncFunction构造函数的实例, 并且其中允许使用await关键字。async和await关键字让我们可以用一种更简洁的方式写出基于Promise的异步行为,而无需刻意地链式调用promise。
一. async
async 函数返回的是一个 Promise 对象。async 函数(包含函数语句、函数表达式、Lambda表达式)会返回一个 Promise 对象。如果在函数中 return 一个直接量,async 会把这个直接量通过 Promise.resolve() 封装成 Promise 对象
async function aa() {
return 111
}
aa()
相当于
Promise.resolve(111)
- 函数加上async函数前缀之后,函数作用域中的部分相当于
new Promise((resolve,reject) => resolve(1233) )
//或者
new Promise((resolve,reject) => reject('出错了') )
所以此时函数作用域内部代码是同步执行的
二. await
await 等待的是一个表达式,这个表达式的计算结果是 Promise 对象或者其它值,
所以,await 后面实际是可以接普通函数调用或者直接量的,所以下面这个示例完全可以正确运行
function getSomething() {
return "something";
}
async function testAsync() {
return Promise.resolve("hello async");
}
async function test() {
const v1 = await getSomething();
const v2 = await testAsync();
console.log(v1, v2);
}
test();
- 如果await后面 不是一个 Promise 对象,那 await 表达式的运算结果就是它等到的东西;
- 如果await后面是一个 Promise 对象,await 就会阻塞后面的代码,等着 Promise 对象 resolve,然后得到 resolve 的值,作为 await 表达式的运算结果,这也是await放在函数作用域里面的原因,即便有阻塞,也是阻塞了函数作用域范围的代码,而不会影响函数外的作用域;
- 如果await后面的函数本身就是返回一个promise,则该函数可不加async前缀。
三. 错误捕获
async function aa() {
let s1 = new Set();
let p1,p2,p3;
p1 = await Promise.resolve(1);
p2 = await Promise.reject(2);
p3 = await Promise.resolve(3)
s1.add(p1);
s1.add(p2);
s1.add(p3);
return s1
}
aa().then(res => {
console.log(res)
})
报错信息
因为p2状态为rejected,会阻塞函数作用域内p2之后的代码执行
捕获错误的方式
1. Promise
aa().then(res => {
console.log(res)
},(err) => {
console.log(err) // 2
})
2. try catch
async function aa() {
let s1 = new Set();
let p1,p2,p3;
try {
p1 = await Promise.resolve(1);
p2 = await Promise.reject(2);
p3 = await Promise.resolve(3)
} catch(err) {
console.log(err,'err1')
}
s1.add(p1);
s1.add(p2);
s1.add(p3);
return s1
}
aa().then(res => {
console.log(res)
},(err) => {
console.log(err)
})
(1) . try catch和Promise错误捕获都存在时,会优先try catch;
(2) . 因为将await相关的代码包裹在try catch中,所以上述代码并不会阻塞try catch之后的代码执行;
(3). 上述try catch的错误捕获,只能捕获到第一个rejected状态的promise实例错误信息,因为阻塞缘故,且只能捕获一个。
3. 如何不受错误阻塞影响,返回成功的promise实例,且抛出rejected状态的promise实例错误信息?
实现代码如下:
async function aa() {
let s1 = new Set();
let p1,p2,p3;
try {
p1 = await Promise.resolve(1);
} catch(err) {
console.log(err,'err1')
}
try {
p2 = await Promise.reject(2);
} catch(err) {
console.log(err,'err2')
}
try {
p3 = await Promise.resolve(3);
} catch(err) {
console.log(err,'err3')
}
s1.add(p1);
s1.add(p2);
s1.add(p3);
return s1
}
四. await阻塞情况
function handleAdd() {
return new Promise((resolve, reject) => {
console.log('hello');
});
}
async function test() {
try {
await handleAdd();
} catch (err) {
console.log(err, 'err12343');
} finally {
console.log('final');
}
console.log(1233, 'testValue');
}
test();
虽然利用try catch可以在一定程度上防止进程阻塞,但是前提是以promise状态已更改为fulfilled或rejected,假如是pending状态,还是会阻塞后面代码执行