当你第一次学习了JavaScript承诺时,你了解了承诺的方法then和catch。前者的回调函数在JavaScript promise成功解决时被调用,而后者则是用来处理错误:
function findUserById(id) {
return database.getUserById(id)
.then(user => { /* do something with user */ })
.catch(error => { /* do something with error */ });
}
最终你了解了JavaScript中的async/await,以替代JavaScript promise的then和catch方法:
async function findUserById(id) {
const user = await database.getUserById(id);
// do something with user
return user;
}
从then/catch到async/await的转变是一个相当强大的转变,因为突然间你又能以同步的方式阅读你的代码了。在 await 语句之后发生的每一行都必须等待,直到承诺解决。此外,像这样写代码感觉更简洁了。但是,还有就是用try/catch块来处理async/await的错误:
async function findUserById(id) {
let user;
try {
user = await database.getUserById(id);
// do something with user
} catch (error) {
// do something with error
}
return user;
}
这又打破了async/await的所有简洁性,因为我们没有在then/catch块中设置异步回调,而是用一个try/catch块来包围所有东西。那么,如果你能从两个世界中获得最好的东西呢?
async function findUserById(id) {
const user = await database.getUserById(id)
.catch(error => {
// do something with error
});
return user;
}
这是可行的,唯一的缺陷是,在出现错误的情况下,await语句之后的所有代码仍然会执行。我们必须用一个条件来保护它,但只有在你需要避免这种行为的时候:
async function findUserById(id) {
const user = await database.getUserById(id)
.catch(error => {
// do something with error
});
if (!user) {
// do something if there is no user
// and return in this if block
// or use if/else instead for returning the user in else
}
return user;
}
我们也可以返回错误并在if块中进行错误处理:
async function findUserById(id) {
const maybeUser = await database.getUserById(id)
.catch(error => error);
if (maybeUser instanceof Error) {
// do something with error
} else {
return maybeUser;
}
}
现在,你没有一个庞大的try/catch块,但有一个保护性的if子句,以防从你的JavaScript承诺中返回一个错误(或什么都没有)。这是否比使用try/catch块更干净,取决于你。也许在某些情况下是这样的,但是,我已经了解到,当与其他开发者在一个代码库中工作时,最好使用try/catch的标准实现来建立一个共同的意识。