摘要:重构总共耗时个工作日。第一个重构原因就是没有引入静态类型,导致查看一个对象结构需要翻来覆去在多个文件中查找。第三是各个状态模块耦合度高,加大了代码维护难度。但如果耦合度过高,往往是因为模块没有细分到位。这个项目也不列外。
不知不觉已是2019年的7月,恍惚之间已工作四年。懵懵懂懂的成长,间歇性努力,实话说,对现在自己取得的成果不大满意。不过,好在时不时顿悟,知道适时作出改变。
此后发文会适当记录一些心路历程,与君共勉。
欢迎Star和订阅我的博客。
本文要点:
什么项目,为何会重构?
怎么重构的?
重构前后对比
什么项目,为何会重构?项目是公司主打业务产品之一的可视化子项目,与其他子项目几乎没有耦合,所以可以多带带拎出来重构。具体业务不作过多描述,主要重构内容为系统组件和一个自研可视化图形库。重构总共耗时30个工作日。
技术主要用Vue2系列和JavaScript。第一个重构原因就是没有引入静态类型,导致查看一个对象结构需要翻来覆去在多个文件中查找。第二是因为之前新增代码模式一般为:“来一个需求加一段代码”,长期积累导致代码结构混乱,可读性差。第三是各个状态模块耦合度高,加大了代码维护难度。
怎么重构的?一、在JavaScript中使用TypeScript。“什么?在JS中使用TS? 闻所未闻。 ” 在看到TS官网手册最后一条"Type Checking JavaScript File"之前,我也这样想。其实,TS和VSCode(一款IDE)结合,也可以实现静态类型检测,只不过使用注释形式,一样支持tsconfig.json和自定义Typing。
type TypeApple = { name: string, count: number }
/** @type {TypeApple} */ const apple = { name: "foo", count: 100 }
二、细化模块分类。一般情况下,模块都会有耦合。但如果耦合度过高,往往是因为模块没有细分到位。如果细化模块?举例,假如有一个模块叫Operation,里面既包含操作相关逻辑,也有操作面板逻辑。随着业务发展,操作面板逻辑越来越多。我们完全可以将操作面板逻辑多带带抽成一个模块OperationPanel。
三、解耦可视化库和Vue/Vuex。写业务的时候,很容易因为方便,在Vue组件或Vuex模块中代码越写越长,越来越难维护。这个项目也不列外。所以重构的时候,多带带将可视化库相关逻辑抽成模块,并使用类Vuex写法(state, getters, mutations, actions)进行管理。
class Counter { // # state /** @type {number} */ count = 0 // # getters get countText() { return `Count is: ${ this.count }` } // # mutations /** @param {number} count*/ SET_COUNT = count => { this.count = count } // # actions /** @param {number} count*/ logCount = ( count ) => { this.SET_COUNT( count ) console.log( this.countText ) } }
四、最后一条,编写可维护性高的代码。这里说两个方法。
第一个是“使用Map”。处理“一个有多类型的数据”需要使用判断,常见有3种方法:If, Switch, Map。If的使用简单粗暴,容易理解。
if ( animalType === "dog" ) { console.log( "Wang!" ) } else if ( animalType === "cat" ) { console.log( "Miao!" ) } else if ( animalType === "bird" ) { console.log( "Jiu!" ) }
Switch可以看做是If的简化。
switch ( animalType ) { case "dog": console.log( "Wang!" ) break case "cat": console.log( "Miao!" ) break case "bird": console.log( "Jiu!" ) break }
而Map针对性最强,并且最简洁、最易于维护。
const logMap = { dog: () => console.log( "Wang!" ), cat: () => console.log( "Miao!" ), bird: () => console.log( "Jiu!" ), } logMap[ animalType ]()
具体使用也哪一种因场景而异,但多数场景下,使用Map可读性更强。
第二个是“使用getters和mutations”。比如定义一个模块的`:operationGetters.js`, 里面提供各种用来获取与操作有关的常量和方法。
export const OPERATION_TYPE_A = 0 export const OPERATION_TYPE_B = 1 export const OPERATION_TITLE_MAP = { [ OPERATION_TYPE_A ]: "Title A", [ OPERATION_TYPE_B ]: "Title B", } export const getOperationTitleByType = type => OPERATION_TITLE_MAP[ type ]
定义mutations则是定义一个提供相关各种变更数据方法的文件。在维护代码的时候,查找变更方法名即可直接找到更改数据的出处。
export const SET_OPERATION_TITLE = ( operation, title ) => { operation.title = title }重构前后对比
代码类型 | 重构前 | 重构后 |
---|---|---|
可视化工具库 | 245kb | 214kb |
组件 | 171kb | 157kb |
状态管理 | 62kb | 60kb |
模块模型 | 15kb | 19kb |
服务请求 | 12kb | 4kb |
常量 | 18kb | 22kb |
工具(Utils) | 15kb | 19kb |
静态类型(TypeScript) | 0kb | 9kb |
合计 | 521kb | 509 kb |
因为边重构边在加新功能,且添加了定义TypeScript静态类型的代码,所以总代码量减少并不多。
不过性能显著提升,最重要的是代码可读性、可维护性大大增强,从而能够更从容地应对新需求。
感谢你花时间阅读这篇文章。如果你喜欢这篇文章,欢迎点赞、收藏和分享,让更多的人看到这篇文章,这也是对我最大的鼓励和支持!
欢迎Star和订阅我的原创前端技术博客。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/105296.html
摘要:而这一次的项目,原本以为开发挺顺利的,但是开发完了,才发现自己犯了一个低级而严重的错,这样的一个失误,我一直耿耿于怀。但是监听用户退出页面微信浏览器上面的那个返回或者关闭按钮却死活不行。也容易犯一些低级的错误。 1.前言 前端从事了超过两年,修复了无数的bug,写了无数的bug;挖了很多次坑,填了很多次坑;犯了很多次错,弥补了很多次,学习了很多次。一般而言,对于bug、坑,都是修复完了...
摘要:获取的对象范围方法获取的是最终应用在元素上的所有属性对象即使没有代码,也会把默认的祖宗八代都显示出来而只能获取元素属性中的样式。因此对于一个光秃秃的元素,方法返回对象中属性值如果有就是据我测试不同环境结果可能有差异而就是。 花了很长时间整理的前端面试资源,喜欢请大家不要吝啬star~ 别只收藏,点个赞,点个star再走哈~ 持续更新中……,可以关注下github 项目地址 https:...
摘要:前端切图神器前端掘金安装前端的基础工作就是把设计师的设计稿还原成前端页面,所以切图是作为一个前端的基本技能。 腾讯 Web 工程师的前端书单 - 阅读 - 掘金作者:link 2014年一月以来,自己接触web前端开发已经两年多了,记录一下自己前端学习路上看过的,以及道听途说的一些书,基本上按照由浅入深来介绍。 JavaScript 入门 《JavaScript权威指南(第六版)》 ★...
阅读 2311·2021-11-15 11:38
阅读 2439·2021-11-15 11:37
阅读 2542·2021-08-24 10:00
阅读 2900·2019-08-30 15:56
阅读 1258·2019-08-30 15:53
阅读 3694·2019-08-29 18:43
阅读 2929·2019-08-29 17:01
阅读 3254·2019-08-29 16:25