导读
首先值得肯定的是在异步代码组织中 async/await 确实起到了很棒的作用, 书写代码更加流畅. 尤其是在作用域的处理上, 让异步返回值和异步函数调用时的作用域保持相同.
- // es5
- // 假设 bar 函数返回一个有效的 promise
- function foo () {
- return bar().then(res => {
- console.log(res); // 1
- })
- console.log(res); // error
- }
复制代码
- // es7
- // 假设 bar 函数返回一个有效的 promise
- async function foo () {
- let res = await bar();
- console.log(res); // 1
- }
复制代码
在相同的作用域下可以调用异步返回值, 这样的代码阅读起来更加符合直觉.
但在异常处理的时候, async/await 却变得异常复杂, 本文就讲讨论如何尽可能优雅的优化这个问题.
异常处理
所谓成也萧何败也萧何, 在 async/await 异常处理的时候需要引入 try/catch 来解决程序异常或者 reject, 但这又引入了一个子作用域干扰了代码的流畅性.
我们来看一点代码, 我将展示 try/catch 是如何隐式的创建了一个新的作用域.
- // es7
- try {
- let a = true;
- } catch (e) {
- let a = false;
- }
- console.log(a);
- // 编译后
- // es5
- "use strict";
- try {
- var _a = true; // 实际上 try catch 的花括号内是子作用域
- } catch (e) {
- var _a2 = false;
- }
- console.log(a); // error
复制代码
因为 try/catch 有隐式创建作用域的特性, 这会让在花括号中申明的变量无法被外部访问到, 这很容易让代码容易出错, 并且书写起来很不流畅.
下面就是应用了 try/catch 的 async/await 函数.
- // es7
- // 假设 bar 函数返回一个有效的 promise
- async function foo () {
- let res, err;
- try {
- res = await bar();
- } catch (e) {
- err = e;
- }
- if (err) {
- return 'error occur';
- }
- return res;
- }
复制代码
利用解构
既然 try/catch 的作用域令人头疼, 那么我们也可以利用 es6 中解构的特性来优化一下代码.
- // es7
- // 假设 bar 函数返回一个有效的 promise
- async function foo () {
- let [err, res] = await to(bar());
- if (err) {
- return 'error occur';
- }
- return res;
- }
- function to (promise) {
- return promise
- .then(res => {
- return [null, res];
- })
- .catch(err => {
- return [err];
- })
- }
复制代码
函数 to 帮我们把 promise 按照一个标准的格式返回一个数组, 而这个数组最终都会使 promise 进入 resolve 状态, 因此就可以避免使用 try/catch 结构.
如果在项目中, 可以把函数 to 单独封装成一个模块使用.
- // to.js
- export default function to (promise) {
- return promise
- .then(res => {
- return [null, res];
- })
- .catch(err => {
- return [err];
- })
- }
复制代码
这篇文章是对 如何不用 try/catch 还能优雅使用 async/await https://blog.grossman.io/how-to-write-async-await-without-try-catch-blocks-in-javascript/ (英文且需科学上网) 这篇文章的实践和解读.
来源: https://juejin.im/post/5b727f546fb9a009c72caf79