上一章我们说过了Promise,其实使用上已经足够。就是在理解上,还需要自己多动手敲一些代码;今天来说说另一个异步请求,是ES7中的新方法async...await...
。
那么我们知道了异步请求的优势,也知道可以使用回调函数或者更好的方法Promise来处理异步,那么为什么还要有引入新的异步方法?
答案是Promise也有缺点:
首先Promise的代码还达不到很简洁的程度(如果有太复杂的异步,代码也会很复杂,可读性不高);
其次不能像同步代码一样方便获取到错误信息;
那么async/await怎么用,我们从字面意思理解:async:异步;await:等待
async 是异步的意思,是一个关键字,将 async 关键字放在函数前边,表示某个函数就是一个异步函数,这样就不会影响下边线程的执行顺序,那么为什么有这个关键字就会变成异步请求?我们打印一下带有关键字的函数看一下:
async function foo(n){
return n
}
console.log(foo(222))
控制台会打印出这样:
会神奇的发现,打印出来的是一个带有Promise对象,并且resolved完成状态,结果返回了222。
所以,async函数是包装成了Promise对象作为的返回值 => Promise.resolve(value)
await是等待的意思,放在要异步操作的方法前边。在异步函数当中,等待一段要发生的代码,返回后再向下执行,在没返回值之前,当前异步函数中await后的代码暂不执行。我们看两个重要的例子,仔细看一下:
// 随便写一个延迟函数
function result() {
setTimeout(() => {
console.log('异步请求')
}, 2000);
}
// 然后使用这个方法,先用一个await
async function foo(){
console.log('111')
await result();
console.log('222');
}
foo()
console.log('333')
打印结果如上,函数照常执行,所以先打印了111,然后遇到了await等待关键字,发起了异步请求,所以222是在333之后打印的,在等待2秒之后,最后打印出“异步请求”。
那么如果我把await关键字去掉会怎么样?
// 随便写一个延迟函数
function result() {
setTimeout(() => {
console.log('异步请求')
}, 2000);
}
// 然后使用这个方法,先用一个await
async function foo(){
console.log('111')
result();
console.log('222');
}
foo()
console.log('333')
结果是:
可以看出,222不再受到await影响,按照了111、222、333正常打印。
问题来了:
- 那await加与不加有什么用呢?2秒钟后不都可以打印出“异步请求”四个字吗?
- 上边所说的 “ 在异步函数当中,await等待一段要发生的代码,返回后再向下执行,在没返回值之前,当前异步函数中await后的代码暂不执行 ” 这句话也没有得到验证,222照常打印出来,又是什么原因?
原因请注意上述代码,result函数并不是异步函数,仅仅只是个带有延迟的函数,如果我更改一个result函数,加上Promise,使它成为一个异步函数,我们再来看一下:
// 此刻我们写一个异步方法
function result() {
return new Promise((resolved,reject)=>{
setTimeout(() => {
resolved(console.log('异步请求'))
}, 2000);
})
}
// 然后使用这个方法,需要用到await
async function foo(){
console.log('111')
await result();
console.log('222');
}
foo()
console.log('333')
打印结果如下:
先打印出111和333,2秒钟过后,打印出“异步请求”和222,所以这也是证明了 async/await 是操作异步方法,在返回结果之前,await后的代码,是不执行的。
async/await可以捕获到错误信息,利用try...catch,只需要在要捕获的地方加上这个方法即可:
function result() {
return new Promise((resolved,reject)=>{
setTimeout(() => {
reject(console.log('异步请求'))
}, 2000);
})
}
// 然后使用这个方法,需要用到await
async function foo(){
console.log('111')
try{
await result();
console.log('222');
}catch(err){
console.log(err)
}
}
foo()
console.log('333')
上边的undefined就是错误信息,只不过这个案例没有错误信息;在实际项目中,有一些错误,我们就可以用这种方式捕获到错误信息,(try...catch
语句用于处理代码中可能出现的错误信息),如果用在Promise当中,捕获错误信息就会很麻烦。这也是async的一个优点。
这样看起来 async/await 的写法,很像同步的写法,但是却可以像Promise一样去处理异步,这就是一种代码简洁的好处,如果有多个异步需要处理,不再需要像Promise那样很多 .then
代码横向发展,我们来做一下对比,例如有ABCD四个异步需要触发:
Promise写法
const result = () => {
return aaa()
.then(() => A())
.then(() => B())
.then(() => C())
.then(() => D())
}
result()
.catch(err => {
console.log(err);
})
async/await写法
const result = async () => {
await A()
await B()
await C()
await D()
}
result()
.catch(err => {
console.log(err);
})
上述的代码,只是为了证明async/await写法的可读性会更好,我们在写项目时,在返回的结果中会做很多处理,这种写法在多层嵌套中,你就会发觉它的优势了。
以上就是简单介绍关于async/await的用法,还有很多的用法,例如取中间值,All方法等等,同学们可以进一步去查阅资料,在实际项目中,掌握以上的关键的知识点,是必要的。
有兴趣的同学也可以查询async/await的原理,包括进一步学习关于generator函数,并且可以在评论区留言,共同进步。
weChat:VillinWeChat
欢迎提出宝贵意见