菜单

自是何其闲得蛋疼呀,

2018年11月15日 - CSS/CSS3

而一定是闲得蛋疼才重构的吧

2018/07/25 · 基础技术 ·
重构

原稿出处: 奇舞团 –
hxl   

乘机“发布”进度长达移动及100%,重构的代码终于上线了。我发自了镇母亲般的围笑……

近年来关押了平首文章,叫《史上最烂的出项目增长啥样:苦撑12年,600几近万执行代码》,讲的凡法国的一个软件类,因为各种奇葩之案由,导致代码质量惨不忍睹,项目多年无法提交,最终还有公司领导入狱。里面有一对细节让丁啼笑皆非:一个右键响应事件需要花费45分钟;读取700MB的数据,需要花7龙时间。足见此软件的特性有差不多闹心。

倘叫笔者来接任这“坨”代码,内心都飘过无数个敏感词。其实,笔者自己也保障在相同模仿陈酿了将近7年之代码,随着后辈的添油加醋……哦不,添砖加瓦,功能逻辑日益复杂,代码也转移得臃肿,维护起来步履维艰,性能也非顺利。终于发生同一龙,我闻了心灵之魔鬼在呼唤:“重构吧~~”

重构是一模一样起磨人的事情,轻易而不得。好当兄弟等齐心协力,各方资源也相当形成。我们小步迭代了大半年,最后一抖作气,终于成功了。今天同大家享用一下这次重构的经验和收入。

自身是何其闲得蛋疼呀,若未是作老物控,看下蛇精和白龙,真不思浪费两钟头圈即七毛钱特效。不伦不类,都是看正在几乎单人口于“演”戏。最终打怪战,悟空召唤“猴子座”圣衣,丑陋到无忍心。骷髅们像LV
-1(负一等级)般脆弱,有些不开始于都散了。boss战有玩就是看感-要十分如发生金甲还是蜘蛛结合体(恢宏音乐响起)。话说白骨和有些僧吸了那么旷日持久,能挺猴子了吧。佛祖不为问问了小僧,“你肯为?”“I
do” 小僧毫不犹豫地游说。然后time up,
正常是打主角没打完boss会挂,谁知是佛祖说白骨而了结便得了了。此时白骨小僧的感情上升华阶段,你怪自充分,我充分君死。悟空傻眼了,一个凡是引发之同类啊,一个凡好基友啊,怎么能够为他俩在一起。悟空下不了手啊。
无奈双方感情到死,小僧不要高达黄泉错过送MM,让MM从黑夫人洗成白姑娘。。。取了经后即刻段姻缘可以补充上,拍成后传吧。

参考

Chrome 中的 First Meaningful
Paint

Using SVG

Modern JavaScript Explained For
Dinosaurs

1 赞 收藏
评论

图片 1

3. 优化图片

尽管如此代码做了众优化,但是动辄几十到几百KB的图片转推压了劳动重构带来的升级。所以图片的优化也是非同小可滴~

1. PNG改成SVG

出于项目曾支持IE6-8,大量施用了PNG,JPEG等格式的图。随着历史之车轱辘滚滚向前,IE6-8的用户占比已经大大降低,我们于上年舍了针对性IE8-的支持。这样一来就会用重新不错的缓解方案啦~

俺们的页面及闹各种大小的图标和不同类型的占据位图。原先用位图并无可知充分好之适配retina显示器。现在移化SVG,只需要一致仿图即可。相比PNG,SVG有以下优点:

  1. 压缩后体积小
  2. 不过缩放,不失真
  3. retina显示器上清晰

2. 进一步“压榨”SVG

尽管更换成SVG,但是还远远不够,使用webpack的loader可以使得地压缩SVG体积。

SVG本身既是文件也是图表。设计师提供的SVG大多发生冗余的内容,比如有的不算的defstitle等,删除后并无会见下滑图片质量,还会减多少图体积。

俺们利用svgo-loader对SVG做了一些优化,比如失去丢无用性,去丢空格换行等。这里虽无细数它会提供的优化项目。大家可以对比svgo-loader的挑配置。

此外,SVG有多用法,比如:img,background,inline,inline
<use>。如果某些图反复起同时对页面渲染很关键,可以下svg-sprite-loader以多单图合并成一个不胜之SVG,避免逐个倡导图片请。然后下内联或者JS加载的道拿之SVG引入页面,然后以用之地方以SVG的<use>标签引用该图标。合并后的大SVG如下图:

图片 2

使用时:

<svg> <use xlink:href=”#icon-add”></use> </svg>

1
2
3
<svg>
  <use xlink:href="#icon-add"></use>
</svg>

即可在以的位置展现该图标。

上述是部分优化手段,下面被大家分享一下重构后底纯收入。

1. HTML瘦身

在利用组件化开发前,HTML中预置了过多签元素,比如:

JavaScript

<button data-cn=”del” class=”del”>删除</button> <button
data-cn=”rename” class=”rename”>重命名</button> …

1
2
3
<button data-cn="del" class="del">删除</button>
<button data-cn="rename" class="rename">重命名</button>

当状态改变时,通过JS操作DOM来控制预置标签的情节或展示隐藏状态。这种做法不仅为HTML很臃肿,JS跟DOM的紧耦合也让人口头异常。改成为组件化开发后,将这些要素都删掉。

事先还运用了重重全局变量存放服务端输出的数。比如:

<script> var SYS_CONF = { userName: {%$userInfo.name%} … }
</script>

1
2
3
4
5
6
<script>
    var SYS_CONF = {
        userName: {%$userInfo.name%}
        …
    }
</script>

乘机年华的推,这些全局变量越来越多,管理起挺棘手。还有一对早就丢之变量,对HTML的体积做出了“贡献”。所以重构时就保留了必备的变量。更多数据则以运转时加载。

另外,在无模板字面量的年份,HTML里大量采用了script标签存放运行时所欲的模版元素。比如:

<script type=”text/template” id=”sharePanel”> <div
class=”share”> … </div> </script>

1
2
3
4
5
<script type="text/template" id="sharePanel">
    <div class="share">
        …
    </div>
</script>

尽管上线时会见管这些标签内之字符串提取成JS变量,以削弱多少HTML的体积,但在支付时,这些script签会加代码阅读之难度,因为一旦无停止地切换HTML和JS目录查找。所以重构后删掉了大量的<script>标签,使用vue的<template>跟ES6的沙盘字面量来管理模板字符串。

愈来愈优化

2. 逐年进渲染

首屏想只要重快渲染,还要保证文档加载的CSS和JS尽量少,因为她会堵塞文档加载。所以我们尽量延迟加载非关键零部件。比如:

单页应用来为数不少总长由于组件。所以除了默认跳转的路由组件,将非默认路由组件打包改成独立的chunk。使用import()的法子动态加载。只有命中该路由时,才加载组件。比如:

JavaScript

const AsyncComp = () => import(/* webpackChunkName: “AsyncCompName”
*/ ‘AsyncComp.vue’) const routes = [{ path: ‘/some/path’, meta: {
type: ‘sharelink’, isValid: true, listKey: ‘sharelink’ }, component:
AsyncComp }] …

1
2
3
4
5
6
7
8
9
10
11
const AsyncComp = () => import(/* webpackChunkName: "AsyncCompName" */ ‘AsyncComp.vue’)
const routes = [{
  path: ‘/some/path’,
  meta: {
    type: ‘sharelink’,
    isValid: true,
    listKey: ‘sharelink’
  },
  component: AsyncComp
}]

这些零部件其实可以推至主要内容渲染了再加载。将这些组件单独从包也一个chunk。比如:

JavaScript

import(/* webpackChunkName: “lazy_load” */ ‘a.js’) import(/*
webpackChunkName: “lazy_load” */ ‘b.js’)

1
2
import(/* webpackChunkName: "lazy_load" */ ‘a.js’)
import(/* webpackChunkName: "lazy_load" */ ‘b.js’)

如若某些意义属于低频操作,或者未是装有用户都亟需。则足以选延迟到用的下重新加载。比如:

JavaScript

async handler () { await const {someFunc} = import(‘someFuncModule’)
someFunc() }

1
2
3
4
async handler () {
  await const {someFunc} = import(‘someFuncModule’)
  someFunc()
}

挑战

本次重构的靶子是一个重型单页应用。它实现了云端文件管理力量,共有10单行程由于页面,涉及文件上传、音视频播放、图片预览、套餐购等几十独职能。前端采用QWrap、jQuery、RequireJS搭建,HTML使用PHP模板引擎Smarty编写。

我们摘了Vue.js、vue-router、vuex来改造代码,用webpack完成模块打包的工作。仿佛一下子自旧社会迈向了新世纪,是勿是怪完美?

图片 3

(图片源于网络)

出于品种比大,为了快速迭代,重构的过渡期允许新老代码并存,开发了部分就测试高达丝一样片,直到最后完全代替旧代码。

然鹅,我们迅速便发现及一个问题:重构部分以及新增需求无法保证同一。比如重构到一半,线及力量转移了……产品未会见等于重构了再向前方发展。难休成要在新镇代码中互迭代相同之求?

别慌,一定能够想发双重快捷之解决办法。稍微分析一下,发现我们如果拍卖三种状况:

1. 成品需要新增一个功力。比如一个平移弹窗或路由于页面。

釜底抽薪办法:新效能因此vue组件实现,然后手动加载到页面。比如:

JavaScript

const wrap = document.createElement(‘div’)
document.body.appendChild(wrap) new Vue({ el: wrap, template: ‘<App
/>’, components: { App } })

1
2
3
4
5
6
7
const wrap = document.createElement(‘div’)
document.body.appendChild(wrap)
new Vue({
  el: wrap,
  template: ‘<App />’,
  components: { App }
})

若果这个组件必须和老代码交互,就用零件暴露于全局变量,然后由老代码调用全局变量的法子。比如:

JavaScript

// someApp.js window.someApp = new Vue({ … methods: { funcA() { // do
somthing } } })

1
2
3
4
5
6
7
8
9
// someApp.js
window.someApp = new Vue({
  …
  methods: {
    funcA() {
      // do somthing
    }
  }
})

JavaScript

// 老代码.js … window.someApp.funcA()

1
2
3
// 老代码.js
window.someApp.funcA()

在意:全局变量名需要人工协调,避免命名冲突。PS:立即是过渡期的降,不是最后状态

新增一个路由页面时再度难于。聪明之读者必定会想到被新增的路由页面独立于已有些单页应用,单独分配一个URL,这样代码会又彻底。

如新增的路由页面需要实现十几独力量,而这些成效就是吃原代码中吗?权衡了需要的紧急性和针对性代码整洁度的言情,我们还妥协(PS:这吗是过渡期,不是最终状态)。大家不要随意模仿,如果基准允许,还是新起一个页面吧,心情会舒畅很多啊。

2. 活要改老代码里的独门组件。

缓解方式:如果这个组件不是特地复杂,我们会以“夹带私货”的方重构上线,这样还会顺便给测试童鞋帮忙验一下重构后发生没来bug。具体贯彻参考第一种情况。

3. 成品需要改整站的共用部分。

咱俩的网站包含好几独页面,此次重构的单页应用只是里有。它们并用了顶部导航栏。在这些页面模板被通过Smarty的include语法加载:

JavaScript

{%include file=”topPanel.inc”%}

1
{%include file="topPanel.inc"%}

产品在相同破界面改版中提出要叫导航栏加上有的意义的高效入口,比如导入文本,购买套餐相当于。而这些效应于单页应用被曾经用vue实现了。所以还得拿导航栏实现啊vue组件。

为了还快渲染导航栏,需要保留它原有的标签,而不是当JS里因组件的形式渲染。所以待运用特殊手段:

<div id=”topPanelMountee”> <div id=”topPanel”>
<div>一些页面直出的情</div> … <import-button>
<button class=”btn-import”> 导入 </button>
</import-button> … </div> </div>

1
2
3
4
5
6
7
8
9
10
11
12
<div id="topPanelMountee">
  <div id="topPanel">
      <div>一些页面直出的内容</div>
      …
      <import-button>
        <button class="btn-import">
          导入
        </button>
      </import-button>
      …
  </div>
</div>

JavaScript

// topPanel.js new Vue({ el: ‘#topPanelMountee’, template:
‘#topPanelMountee’, components: { … ImportButton } })

1
2
3
4
5
6
7
8
9
// topPanel.js
new Vue({
  el: ‘#topPanelMountee’,
  template: ‘#topPanelMountee’,
  components: {
    …
    ImportButton
  }
})

根重构后,我们还开了越来越的特性优化。

重构的低收入

以下是重构带来的收入:

收益项 重构前 重构后
组件化 100%
模块化 50% 100%
规范化 ESLint 代码规范检查
语法 ES5 ES6+
首屏有效渲染时间 1.59s 1.28s(提升19%)
首次交互时间 2.56s 1.54s(提升39%)

如上就是是这次重构的下结论。不要容忍代码里之坏味道,更不用容忍低效的支付模式。及时发现,勇敢改进吧~

相关文章

标签:

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图