如何理解 JS的 async/await

async/await到底是什么?

从字面上理解,async 是“异步的意思,而 await 我们可以简单的认为是 async wait 的简写。所以, async 用于申明一个 function 是异步的, await 是用于等待一个异步方法执行完成。
语法规定,async 表示函数里有异步操作,await 表示紧跟在后面的表达式需要等待结果, await 命令只能用在 async 函数之中,如果用在普通函数,就会报错。

async怎么用?

举个简单栗子

async function fn() {
  return 'hello world';
}
console.log(fn()); 

结果如下:
控制台结果
由此可见,如果在函数中 return 一个直接量,async 会把这个直接量通过 Promise.resolve() 封装成 Promise 对象。(通俗讲,async作为一个关键字放在函数前面,它的调用返回了一个promise 对象。)

到这步就有疑问了,返回的是一个promise 对象,那么如何处理这个promise对象获取其返回值?
当然是用原来的方式:then() 链来处理这个 Promise 对象

async函数内部return语句返回的值,会成为then方法回调函数的参数 
fn().then(data=>{
console.log(data)  //输出hello world
})

那么问题又来了,如果 fn 函数内部抛出错误呢?

async函数内部抛出错误,会导致返回的 Promise 对象变为reject状态,
抛出的错误对象会被catch方法回调函数接收到

async function fn(){
	 throw new Error('rejected')
}
fn()
.then(v=>{
	console.log(v)
})
.catch(e=>{
	console.log(e)   // Error:rejected
})

如图:
会调用Promise.reject() 返回一个promise 对象
控制台结果

await怎么用?

await 关键字只能放到async 函数里面,await是等待的意思,那么它等待什么呢?它后面跟着什么呢?
其实它后面可以放任何表达式,不过我们更多的是放一个返回promise 对象的表达式,它等待的是promise 对象的执行完毕,并返回结果

举个栗子:

async function func(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            var a= "lxy";
            resolve(a)
        },1000)
    })
}
async function test(){
    var b = await func();
    console.log(b);
};
test();   // 输出结果 :lxy

分析一下过程:首先调用了test()函数,内部遇到了await,暂停执行代码,直到后面的promise对象也就是func()执行完毕,func()返回的promise开始执行,拿到promise resolve 的值并返回,这时,await拿到返回值并赋值给b,暂停结束,代码接着执行,输出console.log语句。

注意:当js引擎在等待promise resolve 的时候,await并没有真正的暂停工作,它可以处理其它的一些事情,如果我们在test函数的调用后面,console.log 一下,你会发现先执行了后面的console.log代码。

async function test(){
    var b = await func();
    console.log(b);
};
test();   
console.log('先执行')

先执行了console.log语句,隔一秒后再执行了test()方法
控制台结果

为什么要用async/await?

处理由多个 Promise 组成的 then 链的时候,用async/await就会比较方便

举个栗子:

setTimeout(function callback(){
	console.log( 'First' )
},1000)

当我们异步函数需要嵌套的时候,如下

setTimeout(function(){
    console.log("First")
    setTimeout(function(){
        console.log("Second")
        setTimeout(function(){
            console.log("Third")
            setTimeout(function(){
                console.log("Four")
                setTimeout(function(){
                    console.log("Five")
                },1000);
            },1000);
        },1000);
    },1000);
},1000);

看到这,简直要炸了,那我们用async/await来处理一下

function fn(ms){
	return New Promise((resolve,reject)=>{
		setTimeout( resolve, ms, 'finish')
})
}
async function asyncFn(){
	await asyncFn(1000)
	console.log('First  finish')
	
	await asyncFn(1000)
	console.log('Second  finish')
	
	await asyncFn(1000)
	console.log('Third  finish')
	
	await asyncFn(1000)
	console.log('Four  finish')
	
	await asyncFn(1000)
	console.log('Five  finish')
	return 'all finish'
}
asyncFn().then(v=>{
	console.log(v)
})
其实这里的异步函数操作与同步函数操作没什么区别

这样是不是一目了然,结构清晰明了

注:只要有一个await语句后面的 Promise 变为reject,那么整个async函数都会中断执行

那么,万一出现这种情况,如何不影响后续的执行?

这时,我们可以将第一个await放在try…catch结构里面,这样不管这个异步操作是否成功,第二个await都会执行


async function fn() {
  try {
      await Promise.reject('出错了');
  } catch(e) {
  }
  return await Promise.resolve(  'hi' );
}
f().then(v => 
    console.log(v)  // 输出结果:hi
) 

说明:本文参考了阮老师的ES6教程案例以及各大文章自己理解整理出来的,望有不对地方请指正!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值