各种catch写法,你知道多少?

本文详细解析了JavaScript中try...catch和Promise的错误处理机制,包括catch的作用范围、Promise中的catch与外部try...catch的关系,以及finally的执行顺序和返回值优先级。
摘要由CSDN通过智能技术生成

相信在项目中为了维护代码,捕获错误,都是需要在项目中使用catch,今天就让我们来看看各种各样的catch写法,而且在前端领域内,异步问题是经常出现的,那Promise就应该熟记于心了,今天让我们一起来看看各种各样的Promise写法,你真的掌握了吗?

今天主打就是“我画你猜”,看看大家能够猜对多少?

try…catch…

首先来开胃菜, 如果觉得这里的很简单, 可以直接去后面看组合的demo


const getUserInfo = () => {
  return new Promise((resolve, reject) => {
    reject('error')
  })
}

const getList = () => {
  return new Promise((resolve, reject) => {
    resolve('getList')
  })
}

const mounted = async () => {
  try {
    const userInfo = await getUserInfo()
    // 中断不再执行
    const list = await getList(userInfo.id)
  } catch (err) {
    console.log(err) // 输出error(控制台未报错)
  }
}

mounted()

这应该很符合流程和我们的想象,当前面接口出错时,下面的接口显然不能正常执行下去了,因为前面的接口请求,肯定是后面接口请求需要用到的请求参数,不然也不会让getUserInfo这个接口先请求,然后等待接口请求完成之后再进行其他请求.

如果没有try…catch会中断执行吗?如果没有try…catch会控制台报错吗?

如果分别用try…catch包裹两个请求,会怎么样?

如果Promise中有catch,那try…catch还能够捕获到吗?

如果Promise后有catch,没有try…catch会报错吗?

慢慢的,能够发现其实还有很多情况,需要我们慢慢发现,接下来一起来体验揭秘的感觉吧

第一个疑问,没有try…catch会中断执行

const getUserInfo = () => {
      return new Promise((resolve, reject) => {
        reject('error')
      })
    }

    const getList = () => {
      return new Promise((resolve, reject) => {
        resolve('getList')
      })
    }

    const mounted = async () => {
      console.log(1)
      const userInfo = await getUserInfo()
      console.log(2)
      const list = await getList()
      console.log(3)
    }

    mounted()

只有输出了1,然后就中断执行,而且控制台出现报错

所以第一个疑问,也有了答案

为什么会报错,这里其实就是执行getUserInfo时,返回的reject中断了后面的逻辑

第二个疑问:

如果分别用try…catch包裹两个请求,会怎么样?

const getUserInfo = () => {
      return new Promise((resolve, reject) => {
        reject('error')
      })
    }

    const getList = () => {
      return new Promise((resolve, reject) => {
        resolve('getList')
      })
    }

    const mounted = async () => {
      console.log(1)
      try {
        const userInfo = await getUserInfo()
      } catch (err) {
        console.log(err)
      }
      console.log(2)
      try {
        const list = await getList()
      } catch (err) {
        console.log(err)
      }
      
      console.log(3)
    }

    mounted()

整个mounted一直执行完毕,没有报错,但是输出了getUserInfo中的reject的值

原因就是getUserInfo中断了执行,但只中断包裹它最近的try…catch这个作用域,并且由最近的catch捕获到了错误。并不会影响mounted整个函数,getList所以正常执行

promise.catch

单个的try…catch就上面这些,接下来就是promise.catch与try…catch的组合了

疑问三

如果Promise中有catch,那try…catch还能够捕获到吗?

const getUserInfo = () => {
  return new Promise((resolve, reject) => {
    reject('error')
  }).catch(err => {
    console.log('getUserInfo', err)
  })
}

const getList = () => {
  return new Promise((resolve, reject) => {
    resolve('getList')
  }).catch(err=> {
    console.log('getList', err)
  })
}
const mounted = async () => {
  console.log(1)
  try {
    const userInfo = await getUserInfo()
  } catch (err) {
    console.log('user catch', err)
  }
  console.log(2)
  try {
    const list = await getList()
  } catch (err) {
    console.log('list', err)
  }
  
  console.log(3)
}

mounted()

相信经过上面的例子,应该能猜到结果了,出现错误的地方,离最近的catch会抛出错误,其他流程一概不中断,不受影响

疑问四:

如果Promise中有catch,没有try…catch会报错吗?

const getUserInfo = () => {
  return new Promise((resolve, reject) => {
    reject('error')
  }).catch(err => {
    console.log('getUserInfo', err)
  })
}

const getList = () => {
  return new Promise((resolve, reject) => {
    resolve('getList')
  }).catch(err=> {
    console.log('getList', err)
  })
}
const mounted = async () => {
  console.log(1)
  const userInfo = await getUserInfo()
  console.log(2)
  const list = await getList()
  console.log(3)
}

mounted()

到这里,大家就都应该能够回答出正确答案了

mounted函数全部执行

promise

当前面的promise已经reject,后面的then还会继续执行吗?

看下面的demo1

demo1

const p1 = new Promise((resolve, reject) => {
  reject('p1 error')
})

p1.then((v) => {
  console.info('p1 then1 resolve:', v)
}).then((v) => {
  console.info('p1 then2:', v)
}).catch(e => {
  console.info('p1 catch:', e)
})

直接输出了catch,前面的then都没有执行,因为没有捕获错误之前,抛出错误后面的执行会中断

demo2

const p1 = new Promise((resolve, reject) => {
  reject('p1 error')
})
p1.then((v) => {
  console.info('p1 then1 resolve:', v)
}, (e) => {
  console.info('p1 then1 reject:', e) //输出 
}).then((v) => {
  console.info('p1 then2:', v) // 输出
}).catch(e => {
  console.info('p1 catch:', e)
})

then中有两个参数,第一个参数回调能够拿到上一个promise的返回值,第二个参数,如果是回调能够取到上面promise捕获的错误,就相当于是catch,所以下面的没有再继续走catch的输出

then第二个参数有处理异常,就不会透传下一层

demo3

const p1 = new Promise((resolve, reject) => {
  reject('p1 error')
})
p1.then((v) => {
  console.info('p1 then1 resolve:', v)
}, (e) => {
  console.info('p1 then1 reject:', e)
  throw new Error('抛出异常')
}).then((v) => {
  console.info('p1 then2:', v)
}).catch(e => {
  console.info('p1 catch:', e)
})

then第二个参数处理异常后,再抛出新异常,会透传个下一层

这里throw new Error()与return Promise.reject(‘抛出异常’)效果一样,都是抛出错误,下面的p1 catch:会捕获到,不过两者的输出的内容还是不一样的,Error是一个错误对象,输出如上图,Promise.reject(‘抛出异常’)输出的是一个字符串,输出效果如下图

demo4

const p1 = new Promise((resolve, reject) => {
  reject('p1 error')
})
p1.then((v) => {
  console.info('p1 then1 resolve:', v)
}, (e) => {
  console.info('p1 then1 reject:', e)
  return 100
}).then((v) => {
  console.info('p1 then2:', v)
}).catch(e => {
  console.info('p1 catch:', e)
})

then第二个参数处理异常,同时返回resolve状态的数据,透传下一层的就是resolve状态了

promise+finally+return

如果觉得上面这两个知识点很简单,那也没关系,接着来哈,还要复杂情况

try …catch…后面存在finally,那finally的执行时机是怎么样的呢?

try …catch…中既有resolve又有return,则最后取的值是怎样的

demo1

var a = () => {
  return new Promise((resolve, reject) => {
    resolve('a resolve')
  })
}

var b = async () => {
  try {
    var res = await a()
    console.info('b await:', res)
    Promise.resolve('b resolve')
    return 'b return'
  } catch (e) {
    console.info('b e:', e)
    return Promise.reject(e)
  } finally {
    console.info('b finally')
  }
}

b()
  .then((data) => {
    console.info('b() data:', data)
  })
  .catch((e) => {
    console.info('b() e:', e)
  })

先看下结果,看看大家有没有猜对的

很明显,这里不会走到catch逻辑,但是这里有一个return和一个Promise.resolve

我们知道,async…await其实也是一个promise函数,所以b会返回一个promise;

promise后面then取到的是b返回的值,也就是有return的情况下,后面的then取到的是return的值;

如果没有return,则data就是undefined,注意,尽管Promise.resolve中有数据的,没有return的情况下,后面then拿到的数据是undefined,不是resolve中的值;

如果return Promise.resolve(‘b resolve’);这样的话,取到的b data: b resolve

如果a中返回的就是reject呢?看下面的例子

demo2

var a = () => {
  return new Promise((resolve, reject) => {
    // resolve('a resolve')
    reject('a reject')
  })
}

var b = async () => {
  try {
    var res = await a()
    console.info('b await:', res)
    return 'b resolve'
  } catch (e) {
    console.info('b e:', e) // 输出a reject
    return Promise.reject(e) // 再次透传
  } finally {
    console.info('b finally')
  }
}

b()
  .then((data) => {
    console.info('b() data:', data)
  })
  .catch((e) => {
    console.info('b() e:', e) // 输出a reject
  })

可以发现,无论b函数中是否走了try,都会执行finally

而错误想要层层传递,需要在catch中也return一个reject信息,这样在b.then后面才能继续捕获到错误了

如果在finally中还出现return呢?会出现怎样的情况,请接着看下面的例子

demo3

var a = () => {
  return new Promise((resolve, reject) => {
    // resolve('a resolve')
    reject('a reject')
  })
}

var b = async () => {
  try {
    var res = await a()
    console.info('b await:', res)
    return 'b resolve'
  } catch (e) {
    console.info('b e:', e)
    return Promise.reject(e)
  } finally {
    console.info('finally')
    return 'finally return'
  }
}

b()
  .then((data) => {
    console.info('b() data:', data)
  })
  .catch((e) => {
    console.info('b() e:', e)
  })

普通猜测:b.catch–>finally->catch

但是想象很美好,现实不一样

我们发现:

1.最终已finally中的return为准

2.控制台报错了,因为b.catch未捕获到,但b.catch捕获的源头是a函数,所以控制台输出了a reject出错

可以看出,由于finally中还有return,所以覆盖了catch中的return,这样就导致了b.catch中的错误没有传递出来,所以控制台报错了

demo4

跟上面的demo小小变化,finally没有return,b.catch中也没有return,那b().then后面是怎么执行的呢?

var a = () => {
  return new Promise((resolve, reject) => {
    // resolve('a resolve')
    reject('a reject')
  })
}

var b = async () => {
  try {
    var res = await a()
    console.info('b await:', res)
    return 'b resolve'
  } catch (e) {
    console.info('b e:', e)
  } finally {
    console.info('b finally')
  }
}

b()
  .then((data) => {
    console.info('b() data:', data)
  })
  .catch((e) => {
    console.info('b() e:', e)
  })

这又是很神奇的结果

因为会执行b().then()中会输出data为undefined

也就是说尽管b函数中走到了catch中,由于已经输出了a中的reject错误,这里返回默认是Promise.resolve()

demo5

接下来看a函数返回是resolve的情况

var a = () => {
  return new Promise((resolve, reject) => {
    resolve('a resolve')
  })
}

var b = async () => {
  try {
    var res = await a()
    console.info('b await:', res)
    return 'b resolve'
  } catch (e) {
    console.info('b e:', e)
    return Promise.reject(e)
  } finally {
    console.info('b finally')
    return Promise.reject('finally return')
  }
}

b()
  .then((data) => {
    console.info('b() data:', data)
  })
  .catch((e) => {
    console.info('b() e:', e)
  })

经过demo3, demo4,相信demo5大家就应该知道了

b.try输出,执行finally,由于finally中返回了reject,所以b.then进入了catch中

总结

1.reject错误,会由最近的catch捕获,在被最近的catch捕获之前,后面的流程会中断执行

2.finally是在then或者catch之后执行(不会晚于下一层对then或catch的捕获输出慢)

3.最终是什么返回给下一层,如果finally有return,它的优先级是高于且覆盖then或者catch的return的

4.如果finally没有return,就看then与catch里面的返回了,如果catch里面没有再return Promise.reject,那么catch默认return出去的是resolve的,值是undefined

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值