性能优化
性能优化主要分为两类:
- 加载时优化
- 运行时优化
例如压缩文件、使用 CDN 就属于加载时优化;减少 DOM 操作,使用事件委托属于运行时优化。
在解决问题之前,必须先找出问题,否则无从下手。所以在做性能优化之前,最好先调查一下网站的加载性能和运行性能。
手动检查
检查加载性能
一个网站加载性能如何主要看白屏时间和首屏时间。
- 白屏时间:指从输入网址,到页面开始显示内容的时间。
- 首屏时间:指从输入网址,到页面完全渲染的时间。
将以下脚本放在 </head>
前面就能获取白屏时间。
<script> new Date() - performance.timing.navigationStart </script>
在 window.onload
事件里执行 new Date() - performance.timing.navigationStart
即可获取首屏时间。
检查运行性能
配合 chrome 的开发者工具,我们可以查看网站在运行时的性能。
打开网站,按 F12 选择 performance,点击左上角的灰色圆点,变成红色就代表开始记录了。这时可以模仿用户使用网站,在使用完毕后,点击 stop,然后你就能看到网站运行期间的性能报告。如果有红色的块,代表有掉帧的情况;如果是绿色,则代表 FPS 很好。
另外,在 performance 标签下,按 ESC 会弹出来一个小框。点击小框左边的三个点,把 rendering 勾出来。
这两个选项,第一个是高亮重绘区域,另一个是显示帧渲染信息。把这两个选项勾上,然后浏览网页,可以实时的看到你网页渲染变化。
利用工具检查
监控工具
可以部署一个前端监控系统来监控网站性能,上一节中讲到的 sentry 就属于这一类。
chrome 工具 Lighthouse
如果你安装了 Chrome 52+ 版本,请按 F12 打开开发者工具。
它不仅会对你网站的性能打分,还会对 SEO 打分。
如何做性能优化
网上关于性能优化的文章和书籍多不胜数,但有很多优化规则已经过时了。所以我写了一篇性能优化文章前端性能优化 24 条建议(2020),分析总结出了 24 条性能优化建议,强烈推荐。
重构
《重构2》一书中对重构进行了定义:
所谓重构(refactoring)是这样一个过程:在不改变代码外在行为的前提下,对代码做出修改,以改进程序的内部结构。重构是一种经千锤百炼形成的有条不紊的程序整理方法,可以最大限度地减小整理过程中引入错误的概率。本质上说,重构就是在代码写好之后改进它的设计。
重构和性能优化有相同点,也有不同点。
相同的地方是它们都在不改变程序功能的情况下修改代码;不同的地方是重构为了让代码变得更加易读、理解,性能优化则是为了让程序运行得更快。
重构可以一边写代码一边重构,也可以在程序写完后,拿出一段时间专门去做重构。没有说哪个方式更好,视个人情况而定。
如果你专门拿一段时间来做重构,建议你在重构一段代码后,立即进行测试。这样可以避免修改代码太多,在出错时找不到错误点。
重构的原则
- 事不过三,三则重构。即不能重复写同样的代码,在这种情况下要去重构。
- 如果一段代码让人很难看懂,那就该考虑重构了。
- 如果已经理解了代码,但是非常繁琐或者不够好,也可以重构。
- 过长的函数,需要重构。
- 一个函数最好对应一个功能,如果一个函数被塞入多个功能,那就要对它进行重构了。
重构手法
在《重构2》这本书中,介绍了多达上百个重构手法。但我觉得有两个是比较常用的:
- 提取重复代码,封装成函数
- 拆分太长或功能太多的函数
提取重复代码,封装成函数
假设有一个查询数据的接口 /getUserData?age=17&city=beijing
。现在需要做的是把用户数据:{ age: 17, city: 'beijing' }
转成 URL 参数的形式:
let result = '' const keys = Object.keys(data) // { age: 17, city: 'beijing' } keys.forEach(key => { result += '&' + key + '=' + data[key] }) result.substr(1) // age=17&city=beijing
如果只有这一个接口需要转换,不封装成函数是没问题的。但如果有多个接口都有这种需求,那就得把它封装成函数了:
function JSON2Params(data) { let result = '' const keys = Object.keys(data) keys.forEach(key => { result += '&' + key + '=' + data[key] }) return result.substr(1) }
拆分太长或功能太多的函数
假设现在有一个注册功能,用伪代码表示:
function register(data) { // 1. 验证用户数据是否合法 /** * 验证账号 * 验证密码 * 验证短信验证码 * 验证身份证 * 验证邮箱 */ // 2. 如果用户上传了头像,则将用户头像转成 base64 码保存 /** * 新建 FileReader 对象 * 将图片转换成 base64 码 */ // 3. 调用注册接口 // ... }
这个函数包含了三个功能,验证、转换、注册。其中验证和转换功能是可以提取出来单独封装成函数的:
function register(data) { // 1. 验证用户数据是否合法 // verify() // 2. 如果用户上传了头像,则将用户头像转成 base64 码保存 // tobase64() // 3. 调用注册接口 // ... }
如果你对重构有兴趣,强烈推荐你阅读《重构2》这本书。
参考资料:
总结
写这篇文章主要是为了对我这一年多工作经验作总结,因为我基本上都在研究前端工程化以及如何提升团队的开发效率。希望这篇文章能帮助一些对前端工程化没有经验的新手,通过这篇文章入门前端工程化。
如果这篇文章对你有帮助,请点一下赞,感激不尽。