async与await其实就是将Promise与它的链式调用简化,使用起来更简洁。
async
使用async时,必须将它放在function关键字前面。
async function fn() {
console.log('1')
}
fn(); // '1'
async函数是同步执行的
此外,async虽然是异步的意思,但是这个函数是同步执行的,不是异步执行的。
async function fn() {
console.log('1')
}
console.log('2');
fn();
console.log('3')
async函数有返回值
async函数默认就有返回值。
async function fn() {
console.log('1')
}
let result = fn();
console.log(result);
我们发现,它默认返回的是一个Promise,且状态为<fullfilled>,PromiseResult为undefined.
如果我们自己返回一个值呢?
async function fn() {
return 1;
}
let result = fn();
console.log(result);
我们发现,他还是返回的Promise实例,但是PromiseResult的值变为了我们返回的值。
//.....接上面的代码
console.log(typeof result) // 'object' 类型为对象
await
await 可以认为是 async wait 的简写,所以await 用于等待一个异步方法执行完成。
await 只能出现在 async 函数中。
function fn() {
let a = await 'await';
console.log(a);
}
fn();
我们发现,报错的信息是await 仅仅在async function中是有效的。
async function fn() {
let a = await 'await';
console.log(a);
}
fn(); // 'await'
其实await的原理就是使用.then链式调用。
原理:
// 使用promise.then
new Promise((res,err) => {
res('yes')
}).then(data => {
console.log(data); // 'yes'
})
// 改一下方式
let p = new Promise((res,err) => {
res('yes')
})
p.then(data => {
console.log(data) // 'yes'
})
而await就是类似第二种。
let p = new Promise((res,err) => {
res('yes')
});
async function fn() {
let data = await p;
console.log(data); // 'yes'
console.log(typeof data); // string
}
fn();
所以我们可以得出,await后面跟的是一个promise实例,而返回的结果就是这个promise实例的PromiseResult而不是一个实例对象(和then的区别)。
如果我们await后面跟的不是promise实例,那么js会自动帮我们把它转换为resolve()后的Promise实例。
async function fn() {
let data = await 'yes';
console.log(data); // 'yes'
console.log(typeof data); // string
}
fn();
await是异步的
从上面我们得出,await就是.then的语法糖,本质其实就是.then,而在promise那一节我们也得出了,then属于一种异步任务,所以await也属于异步的。
async function fn() {
let data = await 'yes';
console.log(data); // 'yes'
console.log(typeof data); // string
}
fn();
console.log('hahha');
我们可以看出,浏览器会先执行后面的代码(先输出‘haha’),在执行await后面的代码。
await的缺点
其实我们了解了await的运行原理后,我们也就懂了await其实就是让异步代码在async函数里面同步执行,所以这也就会导致一个问题,在async函数里面await后面代码会先等待await执行完毕,在执行await后面的代码,但是await又属于异步的,浏览器又会将异步代码放在一个队列中,等待同步代码执行完毕后,再执行队里里的异步代码。所以,await后面的代码,就会变成‘异步’的了,我想这也就是为啥函数前面要加一个async的原因吧!
async function asy() {
return new Promise((resolve,reject) => {
setTimeout(()=>{
resolve('yes')
},2000)
})
};
async function fn() {
let data = await asy();
console.log(data);
console.log('yeyeye');
}
fn();
console.log('hahha');
我们发现,asy函数要等待2s后才resolve,这也就会让await在2s后才会执行,这也就让await后面的代码也会等待2s后再执行!
async与await处理错误
await不止会返回<fullfilled>状态的promise实例,还可能会返回rejected状态的promise实例。而且如果返回了一个错误,这就会导致我们的程序中断,浏览器不会继续执行后面的代码,那么我们如何处理await返回的错误呢?
async function asy() {
return new Promise((resolve,reject) => {
setTimeout(()=>{
reject('no')
},100)
})
};
async function fn() {
let data = await asy();
console.log(data);
console.log('aaa');
}
fn();
使用try/catch处理错误
async function asy() {
return new Promise((resolve,reject) => {
setTimeout(()=>{
reject('no')
},100)
})
};
async function fn() {
try{
let data = await asy();
console.log(data);
console.log('aaa')
} catch(err){
console.log(err)
}
}
fn();
这也就不会导致报错了!
使用.catch()进行处理
还有一种处理错误的方式是使用.catch的方式:
async function asy() {
return new Promise((resolve,reject) => {
setTimeout(()=>{
reject('no')
},100)
})
};
async function fn() {
let data = await asy();
console.log(data);
console.log('aaa');
}
fn().catch((err) => {
console.log(err)
});
但是我一般用的都是第一种 try/catch的方式。
耶,js要写完了!!