前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Promise 自定义错误捕获

Promise 自定义错误捕获

作者头像
copy_left
发布2022-03-23 14:11:49
7560
发布2022-03-23 14:11:49
举报
文章被收录于专栏:方球方球
代码语言:javascript
复制
async function API(){
  return Promise.resolve({
    status: 200,
    data: {
      id: 'xxx'
    }
  })
}


function status(v: any){
  if(v.status === 404){
    return Promise.reject('404')
  }
  return v
}


function getData(v: any){
  if(!v.data){
    return Promise.reject('data is undefined')
  }
  return v.data
}


async function load(){
    const d = await API().then(status).then(getData)
    console.log(d)
}


load()

这里模拟一个简单的请求过程, 实际开发中除了对数据做业务处理外。 还需要做异常处理。全局错误,中间件错误,本地错误等

错误捕获

模式一

代码语言:javascript
复制
API().then(status).then(getData).catch((e) => {
  if(e === '404'){ ... }
  if(e === 'data is undefined'){...}
  ...
})

将错误处理放在所有处理之后,这种模式对于需要处理全局错误时,会产生大量模板代码,且如果需要处理的错误类型比较多的话。处理函数体积将变得比较臃肿,一些不相关的逻辑混杂在一起

模式二

代码语言:javascript
复制
API()
.then(status)
.catch((e) => {
   if(!!e && e === '404'){
    ....
    return Promise.reject(null)
  }
  return Promsie.reject(e)
})
.then(getData)
.catch((e) => {
  if(!!e && e === 'data is undefined'){
    ...
    return Promise.reject(e)
  }
  return Promise.reject(e)
})

为可能报错的处理段,配置对应的错误捕获。这里有利于拆分不同的错误处理逻辑。但由于Promise不存在中断处理,当前错误捕获后依然会处罚后续逻辑, 所以我们依然需要在每个错误处理中添加错误类型判断。

Promise 反模式

其实大部分情况下,我需要的是一个只针对当前错误的处理模式。进一步的话,就是函数只捕获自身可处理的错误. 不能处理的错误跳过直接向下传递。 这就有点像python的处理方式了

错误代理

代码语言:javascript
复制
API()
.then(status)
.catch(statusError, '404')
.then(getData)
.catch(getDataError, 'data is undefined')

这里用反模式的方式实现类似的功能

代码语言:javascript
复制
type IPromiseSig = Symbol | string | number | Error
type PromiseType<T extends Promise<any>> = T extends Promise<infer U> ? U : never


interface Promise<T>{
  customCatch(cb: Function, filter: (d: any) => boolean): Promise<T>
  
  ignore(cb: Function, sig?: IPromiseSig | IPromiseSig[]):Promise<T>
  capture(cb: Function, sig?: IPromiseSig | IPromiseSig[]):Promise<T>
}

将具体的方法挂载在Promise原型上

代码语言:javascript
复制
// 默认错误标识
const PROMISE_CANCEL: Symbol = Symbol('cancel')
// 忽略指定错误类型
Promise.prototype.ignore = function(cb: Function, sig: IPromiseSig | IPromiseSig[] = PROMISE_CANCEL){
  return this.catch((e: any) => {
    const sigs = Array.isArray(sig) ? sig : [sig]
    return sigs.includes(e) ? Promise.reject(e) : cb(e)
  })
}
// 捕获指定错误类型
Promise.prototype.capture = function(cb: Function, sig?: IPromiseSig | IPromiseSig[]){
  return this.catch((e: any) => {
    const sigs = Array.isArray(sig) ? sig : [sig]
    return sigs.includes(e) ? cb(e) : Promise.reject(e) 
  })
}

使用例子

代码语言:javascript
复制
// ignore
function test1(e: string){
  Promise.reject(e)
  .then(
    () => console.log('1')
  )
  .ignore(
    // 忽略 Error 错误
    (e: any) => console.log('1', e),
    [400]
  )
  .ignore(
    (e: any) => console.log('2', e),
    [404]
  )
  .catch(
    // 捕获任意错误
    (e: any) => console.log(e)
  )
}


test1(400)
// 2 400
test1(404)
// 1 404


// capture
function test2(e: any){
  Promise.reject(e)
  .then(
    () => console.log('1')
  )
  .capture(
    // 忽略 Error 错误
    (e: any) => console.log('1', e),
    [400]
  )
  .capture(
    (e: any) => console.log('2', e),
    [404]
  )
  .catch(
    // 捕获任意错误
    (e: any) => console.log(e)
  )
}


test2(400)
// 1 400
test2(404)
// 2 404
test2(500)
// 500

配合 async await

针对async 做简单处理

代码语言:javascript
复制
interface Promise<T>{
  ...
  capture(cb: Function, sig?: IPromiseSig | IPromiseSig[]):Promise<T>


  to():Promise<[T, null] | [null, Error]>
  ignoreTo(sig?: IPromiseSig | IPromiseSig[]):Promise<[T, null] | [null, Error]>
  captureTo(sig?: IPromiseSig | IPromiseSig[]):Promise<[T, null] | [null, Error]>
}
代码语言:javascript
复制
Promise.prototype.to = function(){
   return this.then((d: PromiseType<typeof this>) => [d, null]  as  [PromiseType<typeof this>, null])
  .catch((e: Error) => [null, e] as [null, Error])
}


Promise.prototype.ignoreTo = function(sigs?: IPromiseSig | IPromiseSig[]){
  return this.then((d: PromiseType<typeof this>) => [d, null]  as  [PromiseType<typeof this>, null])
  .ignore((e: Error) => [null, e] as [null, Error], sigs)
}


Promise.prototype.captureTo = function(sigs?: IPromiseSig | IPromiseSig[]){
  return this.then((d: PromiseType<typeof this>) => [d, null]  as  [PromiseType<typeof this>, null])
  .capture((e: Error) => [null, e] as [null, Error], sigs)
}

使用例子

代码语言:javascript
复制
async function API(e?: any){
  return Promise.reject(e)
}


async function run(){
  // 只对 500 错误做捕获
  const [data, error] = await API(500).captureTo([500])
  console.log(data, error)
}
// null 500

需要注意的是,被忽略的错误是直接向外抛出的,一些后续操作(加载状态重置等)需要通过finally() 处理

代码语言:javascript
复制
let loading = false


async function API(e?: any){
  return Promise.reject(e)
}


async function run(){
  const [data, error] = await API(500).captureTo([500]).finally(() => {
    // 始终会执行
    loading = false
  })
  // 错误被忽略时不会执行
  loading = false
  console.log(data, error)
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022.03.13 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 错误捕获
    • 模式一
      • 模式二
      • Promise 反模式
        • 错误代理
          • 配合 async await
          相关产品与服务
          消息队列 TDMQ
          消息队列 TDMQ (Tencent Distributed Message Queue)是腾讯基于 Apache Pulsar 自研的一个云原生消息中间件系列,其中包含兼容Pulsar、RabbitMQ、RocketMQ 等协议的消息队列子产品,得益于其底层计算与存储分离的架构,TDMQ 具备良好的弹性伸缩以及故障恢复能力。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档