async、await与try、catch
async
是Generator函数的语法糖,Generator函数是ES6提供的异步编程的解决方案
理解:表示函数里有异步操作,async函数可以理解多个异步操作包装成的promise对象
返回值:promise对象
async function add(num1, num2) {
const val = num1 + num2;
return val;
}
add(1, 4)
.then((val) => {
console.log(val);
})
.catch((reason) => {
console.log(reason);
});
函数add的返回值会成为then中回调函数的参数,如果add函数内部有错误或主动抛出错误,返回的 promise会是rejected状态,会被catch接收到
await
作用:
1》一是作为求值关键字;.then的语法糖,可以拿到promise的结果
2》二是将异步操作变成同步操作;await后面的代码执行时机一定是在await后的promise执行后(执行时机有点像写在promise回调中的代码)
await 后面一般跟的是一个 promise 对象,如果不是,会转成一个 resolved 状态的 promise 对象
await语句后的promise变为rejected状态,reject的参数会被catch的回调接收到,而且整个 async 函数会被中断执行,即await后的代码就不会执行了(前提是没有catch捕获)
await必须放在async函数中,不然会报错
async function add(num1, num2) {
const re = await Promise.reject("err");
console.log("await后的promise状态改变后");
const val = num1 + num2;
return val;
}
add(1, 4)
.then((val) => {
console.log(val);
})
.catch((reason) => {
console.log(reason); // 只有这个打印了 err
});
async和await搭配使用
await必须放在async函数中,但是使用async时可以没有await
async中返回的promise的状态
async中返回的promise状态变化有三种原因:
1》执行出错或主动抛出错误:返回一个rejected状态的promise,错误或异常原因就是catch中回调函数的参数
2》遇到return:返回一个resolve状态的promise,return的值 就是then中resolved回调函数的参数
3》await后的promise执行完成,这个promise状态变为resolved,那么只要async中没有错误或主动抛出异常,返回的promise状态就是resolved,否则就是rejected
await后的promise状态变为rejected后,那么后面的代码将不再执行(相当抛出了错误,却没有捕获)
async中返回的promise对象回调函数的参数
1》如果await的promise状态变为resolved,而且async中没报错,没有主动抛出异常,那么async函数的返回值就是参数的值,如果没有 return ,则参数为undefined
2》如果async中由错误或await后的promise状态变为rejected(reject() 的作用就是和throw一样),错误原因就是catch的参数值
错误问题
如何捕获promise中的异步错误
1》try … catch 捕获错误
try catch不能捕获到异步错误,但是await可以将他转为同步,所以可以捕获到
如果由多个await,可以统一放在一个try…catch中
async function add(num1, num2) {
const re = await Promise.reject(10);
console.log(20);
const val = num1 + num2;
return val;
}
add(1, 4)
.then((val) => {
console.log(val);
})
.catch((reason) => {
console.log(reason); // 10
});
上面代码只打印出10,如果没有将await中的代码放入try… catch中,await后的promise状态变为rejected,相当于抛出一个错误 (相当于 throw 10 ),错误在里面没有捕获到,所以后面的代码不会执行,async函数返回一个rejected状态的promise,catch中的回调执行
async function add(num1, num2) {
try {
const re = await Promise.reject(10);
console.log(20);
} catch (err) {
console.log("err", err); // err 10
}
const val = num1 + num2;
return val;
}
add(1, 4)
.then((val) => {
console.log(val); // 5
})
.catch((reason) => {
console.log(reason);
});
打印 err 10 和 5,try…catch捕获到await后面的Promise抛出的错误,打印err 10,由于抛出了错误,所以try中的20不会打印,try…catch后面的代码继续执行,async函数返回一个resolved状态的promise,所以打印出5
2》await后的promise跟catch
async function add(num1, num2) {
const re = await new Promise((resolve, reject) => {
setTimeout(() => {
reject(10);
});
}).catch((err) => {
console.log(err);
});
console.log(20);
const val = num1 + num2;
return val;
}
add(1, 4)
.then((val) => {
console.log(val); // 5
})
.catch((reason) => {
console.log(reason);
});
打印结果 10 20 5;await后的promise对象变为rejected状态后,就会执行里面catch的回调,打印10,await后面的代码,只有当await后的promise改变之后,才会执行,打印20,async函数返回resolved状态的promise,打印5
补充:try catch错误捕获问题(不能捕获到异步错误)
1》setTimeout中的异步错误捕获不到:a没有定义,所以控制台报错,没有捕获到错误
try {
setTimeout(() => {
console.log(a)
}, 10)
} catch (err) {
console.log(err)
}
try catch 与 promise:promise 内部 已经加了 try catch 处理了异常,所以不能冒泡到外面
2》在promise内部使用try catch
new Promise((resolve, reject) => {
try {
reject(3) // 捕获不到,而且会先打印99,再报错:Uncaught (in promise) 3
// console.log(a) // 能捕获到
// throw new Error('这就是个错误') // 能捕获到
console.log(99)
} catch (err) {
console.log(err)
}
})
3》在promise外部使用try catch;执行器函数中都是同步代码
try {
new Promise((resolve, reject) => {
// reject(6) // 捕获不到,先打印777,然后报错:Uncaught (in promise) 6
console.log(a) //捕获不到;直接报错:referenceError: a is not defined,不会打印777
// throw 6 // 捕获不到;先打印777,后报错:Uncaught (in promise) 6
})
} catch (err) {
console.log(err)
}
console.log(777)
4》在promise外部使用try catch;实际上一般是这种,因为promise中一般都是处理异步任务
try {
new Promise((resolve, reject) => {
setTimeout(() => {
console.log(a) //不会打印7,直接报错: Uncaught ReferenceError: a is not defined
// throw 6,//不会打印7,直接报错:Uncaught 6
// reject(6) // 打印7,然后报错:Uncaught 6
console.log(7)
})
})
} catch (err) {
console.log(err)
}
promise中不使用try catch,也没有设置 .then .catch回调函数
new Promise((resolve, reject) => {
reject(3) // 打印88,然后报错:Uncaught (in promise) 3
// console.log(a) // 不会打印88,报错:ReferenceError: a is not defined
// throw 3 // 不会打印88,Uncaught (in promise) 3
console.log(88)
})
结论:promise中如果没有写catch,那么相当于默认加了一个在catch,并且catch中抛出错误throw(err);即使执行器函数是一个同步函数,在里面执行了一个同步任务,发生了语法错误,由于是在回调catch中抛出的错误,是一个异步微任务,所以即使在promise外面套了一层try catch也捕获不到
try catch 如果套在promise外层,没有使用async await是捕获不到错误的