1.async 函数 & await
1.1. async含义
ES2017 标准引入了 async 函数,使得异步操作变得更加方便。
async 函数是 Generator 函数的语法糖。
什么是语法糖?
意指那些没有给计算机语言添加新功能,而只是对人类来说更“甜蜜”的语法。语法糖往往给程序员提供了更实用的编码方式,有益于更好的编码风格,更易读。不过其并没有给语言添加什么新东西。
反向还有语法盐:
主要目的是通过反人类的语法,让你更痛苦的写代码,虽然同样能达到避免代码书写错误的效果,但是编程效率很低,毕竟提高了语法学习门槛,让人齁到忧伤。。。
1.2. async的使用
async
函数使用时就是将 Generator 函数的星号(*
)替换成async
,将yield
替换成await
,仅此而已。
async function show (){
await '33'
}
let p1 = show();
1.2.1 await配合async使用
async function fn(){ // async 表示异步,这个函数里面有异步的任务
let result = await xxxx; // 表示等待await后面的结果需要等待,等出来在处理
}
1.3. async
函数对 Generator 函数的区别:
(1)内置执行器。
Generator 函数的执行必须靠执行器,而async
函数自带执行器。也就是说,async
函数的执行,与普通函数一模一样,只要一行。
(2)更好的语义。
async
和await
,比起星号和yield
,语义更清楚了。async
表示函数里有异步操作,await
表示紧跟在后面的表达式需要等待结果。
(3)正常情况下,await
命令后面是一个 Promise 对象。如果不是,会被转成一个立即resolve
的 Promise 对象。
(4)返回值是 Promise。
async
函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了。你可以用then
方法指定下一步的操作。
进一步说,async
函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而await
命令就是内部then
命令的语法糖。
1.4. async 的特点
- await 只能放到async函数中使用
- 相比generator 语义化更强
- await后面可以是promise对象,也可以是数字,字符串,布尔值
- async 函数返回的是一个promise对象
- 只要await 语句后面的Promise的状态变成reject,那么整个async函数会中断执行
1.4.1 验证async函数返回一个promise对象
async function fn(){
}
console.log(fn()); //Promise
// 使用
async function fn(){
return 'welcome';
}
fn().then(res => {
console.log(res); // welcome
})
1.4.2 如果async函数中出错
async function fn(){
throw new Error('Error 出错了')
}
fn().then(res => {
console.log(res);
}).catch(err => {
console.log(err); // Error 出错了
})
1.4.3 如果await后面的语句出错,函数后面将中断执行
错误在成功之后,错误和成功都会执行
async function fn(){
let a = await Promise.resolve("成功了");
console.log(a);
await Promise.reject('出错了')
}
fn().then(res => {
console.log(res);
}).catch(err => {
console.log(err);
})
// 打印结果
// 成功了
// 出错了
但是如果错误在前,成功将不会执行
async function fn(){
await Promise.reject('出错了')
let a = await Promise.resolve("成功了");
console.log(a);
}
fn().then(res => {
console.log(res);
}).catch(err => {
console.log(err);
})
// 打印结果
// 出错了
1.5. 解决async函数中的报错
如何解决async函数中抛出错误,影响后续代码执行;
这个问题比较严重,虽然是async的特点,但是我又不知道程序什么时候出错,所以我不希望出错的代码影响我后续运行
1.5.1使用 try { } catch (){}
async function fn(){
try{
await Promise.reject('出错了')
}catch(e){
let a = await Promise.resolve("成功了");
console.log(a);
}
}
1.5.2 添加catch 捕获错误
本来await后面的就是promise,那么我们就可以直接使用catch处理
async function fn(){
await Promise.reject('出错了').catch(err=>{
console.log(err);
})
let a = await Promise.resolve("成功了");
console.log(a);
}
其实跟网络打交道的都不保险,你不可能给每一个await后面的promise对象都加catch
1.5.3 统一捕获错误
个人建议,只要有await的地方都try catch掉 然后统一处理结果
try {
let f1 = await Promise.resolve('成功了');
let f2 = await Promise.resolve('成功了');
let f3 = await Promise.reject('出错了');
}catch(e){}
1.5.4 也可以是用Promise.all()方法
如果你多次请求的数据之间没有关联,就可以使用Promise.all()
// async
async function fn(){
let [f1,f2,f3] = await Promise.all([
Promise.resolve('成功了1'),
Promise.resolve('成功了2'),
Promise.resolve('成功了3')
])
console.log(f1);
console.log(f2);
console.log(f3);
}
fn();
同时配合解构处理
例子:
async function show() {
let p1 = await new Promise((res, rej) => {
$.ajax({
url: 'https://jsonplaceholder.typicode.com/todos/1',
success: function (data) {
console.log(data);
res()
},
error: function (err) {
rej()
}
})
});
let p2 = await new Promise((res, rej) => {
$.ajax({
url: 'https://jsonplaceholder.typicode.com/todos/2',
success: function (data) {
console.log(data);
res()
},
error: function (err) {
rej()
}
})
});
}
let pp = show();
generator只是一个过渡期,强烈建议大家用async就可以了