async函数搞懂
- 背景
- async
- await
- await 知识点1
- await 知识点2
- await 知识点三
- await 知识点四
- await 知识点五
背景
背景就是遇到了一个比较烦人的模块,里面的涉及到了大量的async 和 awiat。发现大多人对这个语法糖一知半解,然后大量的滥用,整理一下
async
前置知识:
Promise.resolve('foo) === new Promise(resolve => resolve('foo'))Promise.reject('foo) === new Promise((resolve, reject) => reject('出错了'))
1、async修饰的函数返回一个promise
async function myName() {let result = await Promise.resolve("hello")let result1 = await Promise.resolve("hello1")console.log(result)console.log(result1)
}
myName().then(e => console.log(e))
//hello
//hello1
//undefined (函数没有返回任何的值所以是undefined)---------------------
async function myName() {let result = await Promise.resolve("hello")let result1 = await Promise.resolve("hello1")return ({result,result1})
}
myName().then(e => console.log(e))
// { result: 'hello', result1: 'hello1' }
2、async返回的是一个promise,当async中发生错误,这个错误会使返回的promise变为reject状态,从而可以被,catch捕捉到
async function sayHi() {throw new Error('抛出一个错误')
}
// 以下四种写法是等价的
sayHi().then(e => console.log(e),e =>console.log(e))
sayHi().then(undefined,e =>console.log(e))
sayHi().then().catch(res => console.log(res))
sayHi().catch(res => console.log(res))
3、注意以下用法,以下用法在项目中使用是极多的
i:以下的这种写法就很好理解了,没问题的
function timeout(ms) {return new Promise((resolve) => {setTimeout(resolve, ms);});
}
async function asyncPrint(value, ms) {await timeout(ms);console.log(value);
}asyncPrint('hello world', 50)
// hello world
ii:因为async返回一个promise,所以下述写法完全等同于i的写法
async function timeout(ms) {await new Promise((resolve) => {setTimeout(resolve, ms);});
}
async function asyncPrint(value, ms) {await timeout(ms);console.log(value);
}
asyncPrint('hello world', 50)
// hello world
async function timeout(ms) {await new Promise((resolve) => {setTimeout(resolve, ms);});console.log(8888)
}
async function asyncPrint(value, ms) {let res = timeout(ms)console.log(res) console.log(value);
}
asyncPrint('hello world', 50)
// Promise { <pending> }
// hello world
// 8888
async function timeout(ms) {await new Promise((resolve) => {setTimeout(resolve, ms);});console.log(8888)
}async function asyncPrint(value, ms) {let res = timeout(ms)console.log(res) await timeout(ms);console.log(value);
}
asyncPrint('hello world', 50)
//Promise { <pending> }
// 8888
// 8888
// hello world
async function timeout(ms,b=2) {await new Promise((resolve) => {setTimeout(resolve, ms);});console.log(8888,b)
}async function asyncPrint(value, ms) {let res = timeout(ms,9)console.log(res) await timeout(ms,6);console.log(value);}
asyncPrint('hello world', 5000)
//Promise { <pending> }
//8888 9
//8888 6
//hello worl
以下对比:async await 修饰的A函数内部执行时序肯定是可控的,但是如果想要在 另一个函数B中也可控(也就是B中调用了A,想让A执行完,在执行B的一些逻辑,那么就需要用awiat来修饰A)
async function timeout(ms) {await new Promise((resolve) => {setTimeout(resolve, ms);});
}
async function asyncPrint(value, ms) {await timeout(ms);console.log(value);
}
asyncPrint('hello world', 5000);
// 5s后会打印 'hello world'
-------------------------------
async function timeout(ms) {await new Promise((resolve) => {setTimeout(resolve, ms);});
}
function asyncPrint(value, ms) {timeout(ms);console.log(value);
}
asyncPrint('hello world', 5000);
// 直接就打印'hello world',并不等5s
-----------------------
async function timeout(ms) {await new Promise((resolve) => {setTimeout(resolve, ms);});console.log("打印时机")
}
function asyncPrint(value, ms) {timeout(ms);console.log(value);
}
asyncPrint('hello world', 5000);
// 立马打印'hello world',5s后打印 '打印时机'
await
await命令只能用在async函数之中,用在普通函数中会报错
await 知识点1
- await 命令后面是一个promise对象(可以返回这个promise的resolve时的结果并且可以接收,但是reject时就不可以接收到了会报错(可以利用try catch捕捉到reject的结果,或者使用promise的catch可以捕捉到))
- await后面是简单数据或者负责数据,其实都相当于直接把该值给return出来
async function f() {return await 123
}
f().then(e => {console.log(e)})
// 123async function f() {return 123
}
f().then(e => {console.log(e)})
// 123async function f1() {return await {sex: 'man'}
}
f1().then(e => {console.log(e)})
// { sex: 'man' }async function f2() {await {sex: 'man'}
}
f2().then(e => {console.log(e)})
// undefined
await 知识点2
await后面的promise失败了,如何获取到这个失败的值。async里面如果有多个await修饰的promise,返回的resolve的promis并不会阻塞,会继续往下走,但是遇到reject的promise就会直接return出去(有时我们甚至不需要写return)
async function f() {return await Promise.resolve('对了');
}
f()
.then(v => console.log(v))
.catch(e => console.log(e))
// 对了
await语句前面没有return,但是reject方法的参数依然传入了catch方法的回调函数。这里如果在await前面加上return,效果是一样的。
async function f() {await Promise.resolve('对了');await Promise.reject('出错了');
}f()
.then(v => console.log(v))
.catch(e => console.log(e))
// 出错了
async function f() {await Promise.reject('出错了');
}f()
.then(v => console.log(v))
.catch(e => console.log(e))
// 出错了async function f() {return await Promise.reject('出错了');
}f()
.then(v => console.log(v))
.catch(e => console.log(e))
// 出错了
await 知识点三
- await修饰异步,在async中使用,当promise是resolve时接着往下走
- 任何一个await语句后面的 Promise 对象变为reject状态,那么整个async函数都会中断执行。
1、awiat(直接用),只能接收resolve返回的参数
async function myName() {let result = await Promise.resolve("hello")let result1 = await Promise.resolve("hello1")console.log(result)console.log(result1)
}
myName()
// hello
// hello1
async function myName1() {let result = await Promise.reject("hello")console.log(result)
}
myName1()
// 报错了
------------
async function myName1() {let result = await Promise.reject("hello")console.log(111111111111111)console.log(result)
}
myName1()
// 报错了(console都没走)
2、搭配 try catch 可以用 catch捕捉到reject的错误
async function myName2() {try {let result = await Promise.reject("hello")console.log(result)} catch (error) {console.log('出错了',error)}
}
myName2()
// 出错了 hello
3、try catch ,try内之要有一个promise reject,那么后续的就都不会进行了,直接将第一个reject给catch给出去了
async function myName2() {try {let result = await Promise.reject("hello")console.log(result)let result1 = await Promise.resolve("hello word")console.log(result1)} catch (error) {console.log('出错了',error)}
}
myName2()
// 出错了 hello
----------------------------------------
// 下方demo为了证明,报错后没有再往后走
async function myName2() {try {await Promise.reject("hello")console.log('走不走')let result1 = await Promise.resolve("hello word")console.log(result1)} catch (error) {console.log('出错了',error)}
}
myName2()
// 出错了 hello
myName()返回一个promise,这个promise是reject,所以 f函数里的await后面修饰的也就是一个失败的reject了
async function myName() {throw new Error('抛出一个错误');
}
async function f() {await myName()
}f()
.then(v => console.log(v))
.catch(e => console.log(e))
// Error: 抛出一个错误
await 知识点四
如何解决一个async函数中有多个await,而当一个await reject时,怎么保证接下来的await继续往下走(当然这种场景一般是不会存在哈,如果前后异步没有依赖的话(学到个名次(这种关系叫做—继发)),为何要控制他们时序呢?正是因为有依赖所以才要控制时序,既然有依赖关系,第一个失败了,按道理后续就是不应该继续执行了)
// 上述演示过这个场景,可以看到只要一个错误,就不往下走了
// 任何一个await语句后面的 Promise 对象变为reject状态,那么整个async函数都会中断执行
async function f() {await Promise.reject('出错了')console.log('判断是否走不走')await Promise.reject('接着出错')
}
f().then().catch(e => console.log(e))
// 出错了
- 思路: 用catch处理一下reject,将错误处理一下,那么catch就不会暴露出去了
解决方案1:
async function k() {try {await Promise.reject('出错了')}catch(e) {console.log(e)}try {await Promise.reject('出错了1')}catch(e) {console.log(e)}await Promise.reject('接着出错')
}
k().catch(e => console.log(e))
// '出错了'
// '出错了1'
// '接着出错'
解决方案2:
async function l() {await Promise.reject('出错了').catch(e => console.log(e))await Promise.reject('出错了1').catch(e => console.log(e))await Promise.reject('出错了2').catch(e => console.log(e))await Promise.reject('接着出错')
}
l().catch(e => console.log(e))
//出错了
//出错了1
//出错了2
//接着出错
await 知识点五
问:await后面的错误如何处理?
答:如果await后面的异步操作出错,那么等同于async函数返回的 Promise 对象被reject
sync function y() {await new Promise((resolve,reject) => {throw new Error('出错了')})
}
y().catch(e => console.log(e))
// Error: 出错了
错误捕捉(获取)(上面也提到了,分为两种1、try catch 2、用catch捕捉)
async function j() {await new Promise((resolve,reject) => {throw new Error('出错了')}).catch(e => console.log(e))
}
j()
// Error: 出错了
async function j() {try {await new Promise((resolve,reject) => {throw new Error('出错了')})} catch(e) {console.log(e)}
}
j()
// Error: 出错了
分割线------------------------------------------------------
function name() {try {throw new Error('出错了');console.log(1111);} catch (e) {console.log(e);}}
如果抛出错误 throw new Error 就不在往下走了,不会执行执行打印,走到了catch
async onSubmit() {this.lastClickEvent = this.CLICK_EVENT.ADD;try {await this.commonAdd();this.$message({type: 'success',message: this.$t('msg_success')});if (this.isClient) {this.SynchronizeResourceUpdate();}if (!this.accessGuide) {this.back();}} catch (error) {console.log(error);}},
commonAdd如果有throw new Error也就不往下走了,try catch被中断