封面图
CodeReview现场
背景
当前项目已经接入了公司自研的前端监控平台,已经有能力对线上运行的各个项目进行错误监控,并且可以统计相关报错信息及日志。
对于报错问题的修复前段时间也一直在跟进,并且国庆前期错误峰值一度控制在两位数以内,但是近期随着业务的迭代,无暇顾及日志问题的修复,因而错误峰值又有所回升。
根据对报错日志的简单分析,很大一部分错误是因为我们在代码的编写过程中的细节问题引起的,比如:
- cannot read properties of undefined
- obj.img is null
等诸如此类的问题,为了提高代码质量,降低错误峰值,提升开发人员的整体素质,项目负责人决定实行CodeReview制度,每月一至两次。
CodeReview流程
一次成功的CodeReview,大致的流程如下:
- 预约会议室,并邀请需要参会的人员
- 会议开始后,主要讲解人要首先大致讲解一下此次CodeReview涉及的功能模块
- 主要讲解人大致讲解一下该功能模块的页面布局逻辑,所使用的组件,及组件接受的props以及组件对外暴露的方法等
- 带领大家整体Review一遍业务代码
- 在整体Review代码的过程中,大家提出问题,讨论并定制该问题的解决方案
此次CodeReview中涉及的问题
虽然大家每天都在写业务代码,每天都在对业务进行迭代,开发速度很快,并且能够保证功能的正常使用,但是在CodeReview的过程中,依然发现很多值得注意的问题,比如:
- 忘记判空处理
这种场景常见于在请求接口之后,对数据的处理时,比如:
// 处理用户数据
const dealUserFormat = (users) =>{
return users
}
const getData = async () => {
const {data} = await fetchUserList()
let res = dealUserFormat(data)
}
上面的代码中,正常情况下是没有问题的,因为在请求接口的过程中,前端通常会对请求做全局的拦截处理。但是,当后端返回的字段中少了某些字段时,会出现一些其他的问题,比如:接口正常返回,但是界面没有任何反应等情况。
- 前端异常提示的处理
这种情况通常出现在对错误的捕获处理中,比如:
try{
const getData = async () => {
const {data} = await fetchUserList()
let res = dealUserFormat(data)
}
await getData()
}catch(err){
console.error("错误信息:" +err);
}
虽然我们对错误进行了捕获,也通过console.error
打印到了控制台,但是当真正出现错误时,用户根本不知道具体发生了什么事情,对用户体验来说,并不是十分友好。
- 参数必须定义指定类型,用于编译时提示,禁止出现
any
类型的定义
vue3 搭配typescript ,一个非常好的地方就在于ts可以在编译时将问题抛出。同时,我们将我们用到的各种类型定义好之后,ts可以进行类型推断。
另一方面,即便将来更换不同的开发人员进行开发,其他人也可以根据定义好的数据类型快速的分析代码,对项目进行开发迭代。
当我们使用any
进行类型定义时,意味着所用的类型都可以使用,也意味着我们放生了很多我们预测不到的错误。
- 类型声明后,代码中可以自动推断相关类型
使用ts进行开发,有一个很好的点就是项目合理配置后,代码会自动进行类型推断,其表现如下:
handClick方法虽然没有定义返回值,但是当鼠标滑过函数名称时,会自动推断该函数的返回值为void
。
- 索引化类型的使用
因为我们的项目需要处理大量的数据,因而后端接口返回的数据,有时候对象的字段数量或名称并不固定,因而很难去统一定义某某个接口的数据的类型,这时候需要用到索引化类型。
export interface UserInfoItem {
color?: string;
width?: number;
[propName: string]: any;
}
有了[propName: string]: string;
就表示UserInfoItem
可以以有任意数量的属性,并且只要它们不是color
和width
,那么就无所谓它们的类型是什么。
- 类型断言写法 ,判断类型的写法 as 的使用
当某些接口所需的字段很多,或者复杂数据的遍历,我们有可能需要进行类型断言。
拿 createSquare
例子来说,这个例子源于官方文档:
interface SquareConfig {
color?: string;
width?: number;
}
function createSquare(config: SquareConfig): { color: string; area: number } {
// ...
}
let mySquare = createSquare({ colour: "red", width: 100 });
注意传入createSquare
的参数拼写为*colour
*而不是color
。 在JavaScript里,这会默默地失败。
你可能会争辩这个程序已经正确地类型化了,因为width
属性是兼容的,不存在color
属性,而且额外的colour
属性是无意义的。
然而,TypeScript会认为这段代码可能存在bug。 对象字面量会被特殊对待而且会经过 额外属性检查,当将它们赋值给变量或作为参数传递的时候。 如果一个对象字面量存在任何“目标类型”不包含的属性时,你会得到一个错误。
// error: 'colour' not expected in type 'SquareConfig'
let mySquare = createSquare({ colour: "red", width: 100 });
绕开这些检查非常简单。 最简便的方法是使用类型断言:
let mySquare = createSquare({ width: 100, opacity: 0.5 } as SquareConfig);
以上是这次CodeReview中遇到的一些问题,由于时间的关系,大家只讨论了一个小时,但是效果还是非常好的,发现了一些问题,并充分进行了讨论,对以后的开发工作大有裨益。
CodeReview发现的其他问题
除了代码中发现的问题,还有一些和用户体验相关的问题,比如:在客户端开发过程中,我们需需要注意设计稿的还原度。在web端的开发中,我们需要充分考虑到交互效果,和用户体验。
虽然这部分内容并不影响功能的使用,但是作为一个优秀的前端开发工程师,我们还是需要完成从99% 到 100% 的这么一步的跨越的。