如何优雅的处理Promise错误?

更新日期: 2019-11-01阅读: 2k标签: 错误

Promise的出现,成功的将广大前端开发者从回调地域的深渊中拯救了出来,而后还有Async/Await,这两者使得开发者更容易编写异步代码,然后当处理错误时,貌似就不是那么的美好了。

先模拟一个请求操作:

const fetchData = (url, shouldReject = false) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      shouldReject ? reject('error') : resolve('this is data');
    }, 1000);
  });
};

简单回顾一下Promise与Async/Await,例如发起三个请求,使用Promise可以

fetchData('url1')
  .then(data => {
    console.log('data1:', data);
    return fetchData('url2');
  })
  .then(data => {
    console.log('data2:', data);
    return fetchData('url3');
  })
  .then(data => {
    console.log('data3:', data);
  })
  .catch(error => console.log('error:', error));

看起来还不错,这也是Promise比之回调函数的优势在所在,代码看起来很优雅了,但是Async/Await可以更加优雅。

(async () => {
  const data1 = await fetchData('url1');
  console.log('data1:', data1);
​
​
  const data2 = await fetchData('url2');
  console.log('data2:', data2);
​
​
  const data3 = await fetchData('url3');
  console.log('data3:', data3);
})();

代码看起来很优美,甚至Async/Await更加像同步代码,也更符合人的正常逻辑了,但是再看下Promise的例子,所有的异常都在最后处理,那么出现异常的时候,这个异常是哪个请求的呢?难道还要给错误定义类型不成?

当然Promise也可以逐一捕获异常,

fetchData('url1')
  .catch(error => console.log('error1:', error))
  .then(data => {
    console.log('data1:', data);
    return fetchData('url2', true);
  })
  .catch(error => console.log('error2:', error))
  .then(data => {
    console.log('data2:', data);
    return fetchData('url3');
  })
  .catch(error => console.log('error3:', error))
  .then(data => {
    console.log('data3:', data);
  });
// output
// data1:this is data
// error2:error
// data2:undefined
// data3:this is data

可以看到,虽然可以捕获每一个异常了,但是也由于每一层都做了异常处理,导致Promise并不会因为出现reject而终止执行,写起来也很麻烦,这不是我们想要的。

Async/Await是Promise的语法糖,我们可以使用try-catch来捕获异常,也可以使用Promise的catch来捕获。

(async () => {
  try {
    const data1 = await fetchData('url1', true);
    console.log('data1:', data1);
  } catch (error) {
    console.log('error1:', error);
  }
​
  const data2 = await fetchData('url2', true).catch(error => console.log('error2:', error));
  console.log('data2:', data2);
​
  const data3 = await fetchData('url3').catch(error => console.log('error3:', error));
  console.log('data3:', data3);
})();
​
// output
// error1: error
// error2:error
// data2:undefined
// data3:this is data

如果使用Promise的catch来捕获异常,并且对返回值做处理,可以很好的实现异常处理,并且出错阻止往下执行。

(async () => {
  const data1 = await fetchData('url1', true).catch(error => console.log('error1:', error));
  if (!data1) return;
  console.log('data1:', data1);
​
  const data2 = await fetchData('url2', true).catch(error => console.log('error2:', error));
  if (!data2) return;
  console.log('data2:', data2);
​
  const data3 = await fetchData('url3').catch(error => console.log('error3:', error));
  if (!data3) return;
  console.log('data3:', data3);
})();
// output
// error1: error

那么有没有更优雅一点的写法呢?当然是有的,如果对使用Promise的业务函数做一点处理,结合Promise与Async/Await,就可以更加优雅的处理异步业务了。

// 普通未处理的异步函数
const fetchDataPromise = (url, shouldReject = false) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      shouldReject ? reject('error') : resolve('this is data');
    }, 1000);
  });
};
​
// 普通异步函数处理
const fetchData = (url, shouldReject = false) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      shouldReject ? resolve(['error', null]) : resolve([null, 'this is data']);
    }, 1000);
  });
};
// 对异步函数处理
const asyncFunc = (url, shouldReject = false) => {
  return fetchDataPromise(url, shouldReject)
    .then(data => [null, data])
    .catch(error => [error, null])
}
​
// 抽离公共函数处理异步函数
const promiseWrap = (promise) => {
  return promise
    .then(data => [null, data])
    .catch(error => [error, null])
}

有了如上的改造后,业务代码就可以这样写了。

(async () => {
  const [error1, data1] = await fetchData('url1', true);
  if (error1) {
    console.log('error1:', error1);
    // do more thing
  }
  console.log('data1:', data1);
​
  const [error2, data2] = await asyncFunc('url2', true);
  if (error2) {
    console.log('error2:', error2);
  }
  console.log('data2:', data2);
​
  const [error3, data3] = await promiseWrap(fetchDataPromise('url3', true));
  if (error3) {
    console.log('error3:', error3);
  }
})();
// output
// error1: error
// data1: null
// error2: error
// data2: null
// error3: error
// data3: null

这样写就优雅多了,也更加容易处理异常,其实这种处理方法在GO语言中非常常见。

链接: https://www.fly63.com/article/detial/6401

解决Cannot read property range of null 错误

vue工程npm run serve/start/dev启动时,node_modules文件报:Cannot read property range of null 错误,该问题是babel-eslint版本更新问题导致的;

HTTP 400 错误 - 请求无效 (Bad request)

在ajax请求后台数据时有时会报 HTTP 400 错误 - 请求无效 (Bad request);出现这个请求无效报错说明请求没有进入到后台服务里;原因:前端提交数据的字段名称或者是字段类型和后台的实体类不一致

js异步错误捕获

我们都知道 try catch 无法捕获 setTimeout 异步任务中的错误,那其中的原因是什么。以及异步代码在 js 中是特别常见的,我们该怎么做才比较?

不能执行已释放Script的代码

父页面初始化声明变量a为数组(数组对象是引用类型,赋值传递的是地址),创建iframe子页面后给父页面变量a赋值,赋值后销毁iframe子页面,再次调用变量a的时候就会抛出异常‘SCRIPT5011:不能执行已释放Script的代码’。

JS错误处理:前端JS/Vue/React/Iframe/跨域/Node

js错误的实质,也是发出一个事件,处理他,error实例对象message:错误提示信息,name:错误名称(非标准属性)宿主环境赋予

nodejs提示 cross-device link not permitted, rename 错误解决方法

文件上传的功能时候,调用fs.renameSync方法错误,这个提示是跨区重命名文件出现的权限问题。先从源文件拷贝到另外分区的目标文件,然后再unlink,就可以了。

Js中使用innerHTML的缺点是什么?

如果在JavaScript中使用innerHTML,缺点是:内容随处可见;不能像“追加到innerHTML”一样使用;innerHTML不提供验证,因此我们可能会在文档中插入有效的和破坏性的HTML并将其中断

Web前端开发,必须规避的8个错误点!

现在,有越来越多所谓的“教程”来帮助我们提高网站的易用性。我们收集了一些在Web开发中容易出错和被忽略的小问题,并且提供了参考的解决方案,以便于帮助Web开发者更好的完善网站。

web前端错误监控

为什么要做前端错误监控?1. 为了保证产品的质量2. 有些问题只存在于线上特定的环境3. 后端错误有监控,前端错误没有监控,前端错误分为两类: 即时运行错误和资源加载错误

自定义错误及扩展错误

当我们在进行开发的时候,通常需要属于我们自己的错误类来反映任务中可能出现的特殊情况。对于网络操作错误,我们需要 HttpError,对于数据库操作错误,我们需要 DbError,对于搜索操作错误,我们需要 NotFoundError,等等

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!