在网上经常看别人写的文章,自己心血来潮也想写一点。主要思考内容是代码的方式。
感觉自己写的方式很少在别人的文章中或同事的代码中看到,不知道是好还是不好,发出来鉴定一下
(基本无关性能,都是从别人看的时候“更轻松”的角度出发的)
(代码例子都是vue,涉及到一些组件的方法,基本是ElementUI)
1. 使用.catch()代替trycatch来捕捉async/await的错误
async/await基本上算是一个很常用的功能了,经常被用来等待一些异步的任务。正常写业务代码的时候为了安全起见基本会对错误进行捕捉。我经常看到的捕捉方式基本上就是套一层trycatch。包括一些文章写的时候也都是使用这个方法来处理的,但是在实际开发中总觉得trycatch用起来不太顺手。
举一个比较极端的例子(校验表单并发送请求)
//
const API = Promise.reject // 假设我是一个请求
const formData = {} // 假设我是表单数据
// 提交数据
const submit = async () => {
try {
const valid = await formRef.value.validate() // 这里提交失败会走到catch
const res = await API(formData) // 这里接口404会走到catch
// 业务代码
} catch (e) {
// 处理表单的错误
// 处理接口的错误
}
}
遇到的问题
- 业务代码被多嵌套了一层,如果在方法内部还有一些其他操作,可能最后会连续嵌套两三层
- 所有的错误都被同一个catch处理,包括组件的错误、接口的错误等等
- 如果想解决上述的问题,也需要把valid字段和res字段写在trycatch的外层,并且改为let,也有点别扭
但是如果使用.catch()配合await一起使用
const API = Promise.resolve // 假设我是一个请求
const formData = {} // 假设我是表单数据
const submit = async () => {
const isPass = await formRef.value.validate().catch(e => e)
if (!isPass) return
const { code } = await API(formData).catch(e => ({}))
if (code != 200) return
// 业务代码
}
使用.catch()的好处
- 所有代码没有额外的缩进和嵌套
- 所有变量在方法内部都可以访问
- 所有错误分别处理
2. 使用Promise来处理业务逻辑中的交互
这是一个业务逻辑和UI逻辑分离的想法
在写需求的时候,经常遇到的一个功能就是:
用户在点击了一个按钮后,先执行部分逻辑,然后展开一个弹窗,等弹窗的逻辑走完后再走后续的逻辑。
按照我常见的书写方式写了个例子,整体感觉就是业务逻辑直接被UI逻辑给打断了
举一个比较极端的例子(弹出同意协议,确定后进入下一步)
// 第一个触发的事件是 preLogin 也就是用户想登录
// 业务逻辑
const preLogin = () => {
// 判断是否同意了协议
if (!isAgree) {
isDialogShow.value = true
return // 未通过协议就打开弹窗并停止登录
}
realLogin() // 如果通过了协议就正常登录
}
const realLogin = () => {
// 登录
}
// 弹窗相关的代码
const isAgree = ref(false)
const isDialogShow = ref(false)
const handleAgree = () => isAgree.value = true // 切换协议状态
const handleSubmit = () => {
preLogin() // 点击了弹窗的【确定】按钮,再次执行登录
}
如果是自己开发自己维护,整体都没有问题。
但是把例子中的代码直接给别人看
经常会遇到需要多个方法来回跳着看的问题。
先看到preLogin执行了,然后有个isAgree的判断。这个时候就需要跳到下面看isAgree是什么,isDialogShow是什么,然后再看弹窗绑定的方法是不是handleSubmit,最后从handleSubmit回到preLogin
如果业务逻辑涉及到二次弹窗,整个逻辑会再被拆分,直接看的头都大了
使用Promise
// 第一个触发的事件是 login 也就是用户想登录
// 业务逻辑
const login = async () => {
const isAgree = await checkAgree() // 校验是否同意协议并开始等待
if (!isAgree) return
// 通过协议 准备登录
// 登录的代码
}
// 弹窗逻辑
let promiseCallback = () => {} // Promise的回调,绑定在弹窗的确定按钮上
const isAgree = ref(false) // 是否同意协议
const isDialogShow = ref(false) // 弹窗是否暂时
const checkAgree = () => {
if (!isAgree) {
isDialogShow.value = true // 打开弹窗
return new Promise((resolve, reject) => promiseCallback = resolve) // 保存resolve事件,等待弹窗结束
}
return Promise.resolve(true)
}
同样如果是其他开发看这段代码,正常从login方法开始看。1.校验协议 2.完成登录。这段逻辑就结束了。根本不用去看弹窗这段逻辑。
这样写会不会更清晰一些呢?不知道大家怎么看。