5
头图

初来乍到

小z2016年1月1日,来成都找实习工作。但是发现啥也不会,虽然是软件工程专业的,但是用java连接数据库都跑不起来。但是要想拿到三方证明就需要找到实习工作啊。要想找到实习工作就得通过面试,选择什么岗位呢?前端吧,入门简单,先搞定工作再说,心里还想着以后转后端什么的。

兴致勃勃的准备好比脸还干净的简历一波海投。还真收到了好几个面试邀请,一面试

  • 怎么样实现水平垂直居中?
  • 怎么实现等比1:2的图片展示?
  • 清楚浮动有哪些方法?
  • css有哪些选择器,权重是多少?
  • 什么是内联元素,块元素?
  • 什么是盒模型?
  • 怎么用js创建dom并且挂在指定id的标签上?
  • 什么是ajax?
  • em和px的区别
  • 什么是事件委托?
  • 怎么实现动画效果?(那时候还没css3,都是jquery)

初级问题很简单,但是对于当时的我来说一脸懵逼。出了门备受打击,但是我很快的恢复过来,重新进去找到面试官,要了那套面试题,然后回到出租屋里面,一个一个的百度。很多问题的答案我当时看了也是一知半解,但是我都背下了。而且又重新找了类似的问题又看了一遍,然后又信心满满的去参加另一次面试。上面的过程我经历了n次,都没通过,快过春节了,我还是像上班族一样的时间回家,不过工作还没落实下来,时时刻刻惴惴不安。

image.png
年后又回到成都,继续年前的投简历、面试、记录问题、回来针对性的学习、投简历。终于在2016年3月17我面试通过连击科技,整个过程很紧张,但是问题确实回答得很轻松,有几个没答上来的面试官当场就告诉我答案了,实习薪资转正薪资都不高,但是面试官的行为让我觉得是个可以学习的机会,3月21日我入职LIANJI科技(我内心觉得这公司叫“练级科技”)。开启了整整一年多的纯html+css修炼历程,几乎没碰js相关的内容。长达1年多的纯css,熟能生巧,我可以像素级别还原任何设计图,合理组织css可复用块儿,业务强相关的css块儿分离管理互不冲突,形成一个符合当时业务的reset.css base.css common.css business.css。

css实战考虑

  1. 可复用分离

    • reset 重置边距和一些样式的可以单独抽离以便复用
    • base样式,定义常用的自定大小,颜色,边距,浮动,清除浮动等
    • common 组件,设计师设计的东西有很多可以抽象成组件的,列表,详情,分页,header,当时还没有vue,使用css定义好一个就比较容易复用
    .c-header {
     position: relative;
     height: 40px;
     line-height: 40px;
     background: #00965e;
     color: #fff;
    }
    .c-header .left-icon {
     width: 24px;
     height: 24px;
     margin: 8px;
     cursor: pointer;
    }
    
    .c-header .right-more {
     position: absolute;
     right: 10px;
     cursor: pointer;
    }
    
    .detail-list{
     fons-size: 14px;
     line-height: 1.3;
    }
    .detail-list li {
    
    }
    .detail-list li label{
    
    }
    .detail-list li span{
    
    }
    • business 对于具体业务类的css通常变化和差异性比较大,也单独放在一个文件里面
  2. 响应式分离
  3. 使用第三方库

    • animate.css
    • 其他插件带有css,但是样式和产品设计风格不一致,可采用加权覆盖方式处理(css权重)
  4. 栅格系统

    • margin
    • gutter
    • column

    假如边距为20,元素间距为16px;3列。
    怎么实现才是最精炼的呢?评论区见

    .container {
     padding: 0 20px;
    }
    
    .item {
     margin: 0 8px;
    }

    但是我没放弃任何一个向同事请教jQuery,js方面的内容的机会,项目中遇到交互场景我会把html+css写完,然后cope一份开始写js交互,下班的后,找到其中一个后端请教这些问题,怎么动态创建DOM,怎么处理Ajax接口数据返回,怎么写拖拽表格,正则校验金额,js控制弹窗。偶尔讲讲编程心得,不过当时他们聊的东西都更加倾向于应用实战,很多东西他们可以做出来也不一定能讲明白,就算讲了也不一定讲到本质原理,但是我确实是通过他们js正式入门的。linwen的一句话感悟很深

    编程就是数据的增删查改

虽然这话,现在看来不完全对,但是这话让我重新思考js的问题,所谓的动画,dom,各项操作,其实都是拿到不同的数据(dom,data,json),然后对这些数据

进行操作。举一个简单的例子,实现动画效果:

  1. 选择运动目标
  2. 定义目标运动方式,改变目标的属性(位置信息,颜色,透明度等等属性)
  3. 定时器循环执行
  4. 满足条件后终止
简单代码实现
const box = document.createElement("div");
box.style.position = "absolute";
box.style.left = 0;
box.style.width = "20px";
box.style.height = "20px";
box.style.background = "#ddd";

document.body.appendChild(box);

function animate (obj, attrs, time) {
  const {left} = window.getComputedStyle(obj);
  let speed = time / 40;  // 执行次数
  const leftOffset = (parseInt(attrs.left)- parseInt(left))/speed // 每次偏移量
  obj.style.left =  parseInt(left) + leftOffset + "px";
  if(parseInt(left) > parseInt(attrs.left)) {
    obj.style.left = parseInt(attrs.left) + "px"
    return
  }
  setTimeout(()=> {
    animate(obj, attrs, time)
  },40)
}

animate(box, {left: 100}, 2000);
以上是白纸编程未经调试,主要用于解释我当时对DOM编程本质的理解

后面第二年的时候,我的各项技能十分熟练,处理工作十分轻松了,设计师坐我旁边,他绘图,微信的活动页面,微信的其他H5功能,他一边绘图,我一边写html+css,基本上他画完,我也就写完了。然后拿到psd文件吸管取色,切图标,替换就可以转交给后端同事了。这段时间幸福感挺高,虽然工资不高,但是会有剩余,时间比较多,我基本上吃遍成都我看到的想吃的东西,遇到喜欢的还会多吃几次,想去玩儿的地方也没落下,不管多远。

转战VUE

2017年年后,老板给了我一个半成品项目,vue开发的,我从来没接触过,然后就开始学,我也慢慢一步一步摸索将这个项目做出来了,但是我不会发布,而后端同事也不知道怎么打包上线,然后我们就重新按以前mvc模式写了一套。但是当时我意识到这个vue是一个趋势,掌握这个框架可以拿到更高的offer,然后我就开始写学习vue框架,都只做些小组件,我当时照着有道云笔记app的样子,用vue做出来了一套没有数据的静态组件,而且还照猫画虎的把交互都做了很逼真以至于后面面试“YF网络”的时候面试官以为我是用哪个第三方库,但我说我还不会使用第三方库,这个是纯手写的,然后直接面试通过。

坐标成都,1-3年的工程师能封装vue组件找个工作不算太难

面试过程中“YF网络”对我最大的吸引是他们将做的项目使用vue框架,我正好缺少这方面的项目经验。薪资依然不高,比以前稍微多1k,但是我确信跟着把一个项目做下来我的技术水平会有一个大飞跃。试用期我就到一个考验,一来就是vuex做一个视频,回放,切换播放时间的一个项目。压力很大,我vue用得都不太熟,vuex更觉得无比艰难。那几个星期我LOL都没打了,无论做什么事情都在想着vuex和视频怎么联系起来的问题,我很多时候都在看vuex的文档,但是还不太会看文档,但是我就一遍一遍的看,看了很多遍,也没太看懂,有一些概念,但是没法实操。技术总监一直说那个不难,现在我看来那也不难,但是当时就是不会,我在想会不会被fire,因为我第一次找工作时候确实经历过很长时间的煎熬,这一关如果没法突破的话可能以后都只会找更没有机会的工作,而且还不一定能找得到。好在那个视频项目是个半成品,里面本身就有一些vuex的内容,const.js actions.js state.js getters.js mutations.js mapGetters mapMutations,一堆东西目不暇接。有一次照猫画虎,实现了全局定义视频url,action中获取视频,选择不同精彩回放的图片块儿时候传不同的时间参数范围请求同一个视频的不同播放点。现在看来思路还算清晰,但当时做这个时候做完我都不知道怎么实现的。就这样我成功提前转正,开始从零做另一个大型项目。从头开始,每一个环节都有参与,技术经验确实提升很快,而且我以前写HTML+CSS很注意合理性和可读性的优秀习惯很快帮我更好的去封装整个团队都依赖的基础业务组件,一个项目下来封装40多个业务组件。而且都是经常用到的,过程中我对vue的使用更加熟练了。而且自己尝试了nodejs,express,对打包部署方面也可以独立处理。反而vuex在这项目中没怎么用到,我也没继续学习。业务需要我误打误撞实现了单点登录,但当时我不知道这个名词,多个系统,同一套token验证体系,一个系统登录后,其他系统可以直接访问无需登录。

管理后台鉴权

  • 路由配置权限meta
  • 路由拦截(跳转)
  • axios拦截器
  • 部分按钮结合vuex计算是否显示

单点登录

  • 业务系统B访问如果token过期会先询问中心系统,拿到token跳转业务系统B
  • 中心系统如果未登录会先访问业务系统B获取localstorage token,返回中心系统
  • 如果中心系统登录失败,则标记不再跳转,返回中心系统登陆界面

组件封装心得

  • 一个组件代码量过大(200行,400行,看团队情况)考虑拆小
  • 一个组件在2个或以上地方使用到,需要提取成组件
  • 考虑参数和参数类型以及返回事件

    • 预设初始值
    • 组件可选值
    • emit change
    • 表单组件考虑实现modal
  • 一个组件包含多个字段
  • 自定义组件类似于里面有多个值的表单怎么进行校验
  • 业务模块中组合的子组件过多或者出现嵌套考虑上vuex,统一数据源,小心对象getter值修改

image.png

后面我进入一家人力外包公司,到了银行里面工作。这个团队没有前端所以一切都是需要从零开始。
技术选型,项目搭建,脚手架,组件库,编码规则都我一个人说了算,处于学习的目的和好奇,我选择react,现学现用。直接将那个团队的技术栈定格在react领域,后面的人陆续加入,乃至他们组建内部前端团队都是依托于react技术体系(有时候我在想如果当时我一直坚持vue,可能那个团队后面招人,项目开发技术选型上大概率会保持vue的节奏了,冥冥之中,不经意的一个决定还是会影响很多东西)。我当时决定学习react的原因也很狗血,当时找工作的时候发现差不多的工作年限和要求react的薪资平均比vue高1-2k;而且大厂的react岗位多些,现在看来很搞笑,因为两个技术体系很接近,js编程水平到位,框架的使用可以自由切换。框架本身只是快速实现业务的工具

vue和react比较相似,核心方面:组件化思想,数据驱动。其他生命周期,列表,条件,都大同小异。需要注意的是,react组件通讯是通过父组件传入回调函数,而vue通常习惯是emit抛出。使用react过程中收获很多优秀的思想,甚至我会将这些优秀思想在写vue的时候也用上。

  • 拿到设计图后尽可能合理的划分组件
  • 状态提升,单项数据流

后面hooks出来的时候,我率先吃了一批瓜。开发过程中的react组件全部使用hooks + 函数组件。感觉代码量少了很多,而且不用考虑 很多生命周期,和那些繁琐的组件性能优化,诸如(shouldComponentUpdate,pureComponents之类)。hooks这种编程方式很多牛逼的地方:

  • 可以将逻辑相关代码更加集中管理以便于复用,俗称封装自己的hooks;
  • 集中减少变量定义,很多组件都用做得常规操作,比如定义loading, data,pageSize ,pageNumber等信息如果直接使用useState也能做,但是如果自己定义一个结构体对象,可以节省很多行代码
  • 绑定事件监听,取消监听可以集中写在一个代码块里面

初级,中级,高级

偶尔我会思考一个问题,1-3年和3-5年的工程师会有什么区别。引发这个思考的原因是平时写业务代码其实都是table modal form 居多,这些东西我在从事前端开发4个月就已经写得十分熟练了,哪怕后面换成了vue也只用了3个月就完全把这些东西玩儿的很熟,甚至还可以自定义表单,校验,一个FormItem中携带多个字段,动态生成,表单联动。在此基础上大家都是搬砖,凭什么中级前端的工资会比初级前端多很多,而高级前端又比中级前端高很多。截至目前我的定位还是中级前端(20210928)月薪过万,坐标成都。

在我目前看来,相较于初级前端而言中级前端的要有有如下几点:

  • 熟练使用vue框架和周边生态。有充足使用经验的开发者在开发效率和解决问题速度方面会快很多,很多业务场景不用过多的思考如何实现,因为以前的丰富开发经验一下子就知道权限怎么实现,联动表单怎没实现,bug怎么定位,新业务下的组件通过什么方式寻找。
  • 封装的理解更加深刻。如果初级的工程师会使用框架和组件库,那中级的工程师要求能写更通用的组件,业务复杂的组件,虚拟列表,或者其他业务中遇到的比较少见的组件,这些往往没法在市面上找到现成可用的组件,中级前端是一个团队开发中的主力,所以自己造轮子是中级前端必备的基本能力。
  • 代码可读性。如果初级前端写出的代码可以运行,可以满足需求算合格的话,中级前端的代码有更高的可读性要求。

    • className 命按照业务模块和公共模块合理命名
    • 变量名,函数名需要结合全局仔细捉摸
    • 函数体超过30-40行考虑拆分出更小的函数组成
    • 无法一眼看懂的if的条件逻辑判断采用变量命名方式先赋值
    • 重复三次以上的代码必须抽取
    • 相关性强的组件命名用相同前缀+自身名字
    • 项目结构根据相关新适当文件夹分类分类,例如:views,utils,services,components,stores,routes,configs,等
  • 代码性能。
开发效率 + 难点突破 + 代码可读性 + 代码性能

怎么做到呢

  • 平时写业务的时候就有意识的把重复的工作总结出模式,search+table+form+delete+create+upadte。封装基础组件,减少参数数量和简化调用过程。对于不方便提取组件,但是又有特定模式的代码,可以使用 vscode snippet(代码段自动生成)的方式提高生产效率
  • 使用第三方组件库的时候有意识观察优秀作品的API怎么设计,简洁+合理+好记
  • 刨根问底的完备自身知识体系。复杂的问题,都是简单的原理排列组合而成,怎么将json数据转成文件下载?websocket数据实时更新到vue里面时怎么确保数量很大时候不卡,大量数据渲染时候怎么不卡顿,table内部的字段怎么编辑。 基础知识完备,扎实。知识的总量很大,但是社会上知识的增速其实不算太快,很多东西都是在原有的基础上进行的迭代。所以就掌握前端完整知识体系而言我觉得3-5年是可以七七八八的(常用的比较熟悉,不常用的有一定了解)。天赋好,有人带可能会更快。达到90%-100%当然也有可能,但我觉得大部分的读者没那没多的心力去处理这些问题。

中级自检清单

  • 各类css布局场景是否都有自己的解决方式
  • dom编程,查找,创建,编辑,插入节点是否清楚
  • 能否清晰描述dom事件的各个阶段
  • js的数据类型,检测方式,各种检测方式的优劣
  • 函数,闭包,函数内置对象,this,函数调用方式(直接调用,call,apply),引用类型作为函数参数的情况
  • 变量定义的三种方式的异同,关注,临时死区,重复定义
  • 数组能不能回忆起15个及以上个数常用的方法
  • 对象定义,访问,合并,可访问性,对象描述,枚举,原型链,深拷贝
  • 元编程Proxy,Reflect,对对象的各种代理,拓展,副作用
  • 异步编程的 Promise 状态,过程,其包含多个异步处理情况的api是否很熟练
  • 客户端的api,canvas video 全屏,定位,设备信息,客户端存储,自定义富文本,requestAnimationFrame,是否有初步了解
  • 简单的正则能否自己手写。名词+量词+边界断言+flag
  • 字符串,切割,拼接,匹配,填充,判断,截取等常用操作是否熟悉
  • 怎么样合理的组织代码编写函数
  • 怎么抽象定义class
  • 一个对象的行为影响多个对象的时候怎么去降低耦合
  • 经常变动的代码和基本不变的代码怎么做分离
  • 怎么合理的封装vue组件
  • vue的各个生命周期,包括路由赋予的什么周期有哪些,干嘛用
  • watch的使用方法,内置属性
  • computed和watch的区别
  • webpack的配置基本组成有哪些,分别代表什么含义

image.png

我对高级的思考

一切回归本质

我目前的工作内容主要是开发一个行业应用管理系统。包括里面的各种交互。本质上包括,数据获取,数据映射,数据渲染,数据拼装。
使用vue全家桶,起初是一股老全用上,但是后面发现有些地方不该用vuex,就吧vuex移除了,但是后面随着业务变得复杂,有两个地方的组件繁多,数据传递麻烦又重新在局部地区加上。重新思考为什么使用vue

  1. 使用vue解决组件化复用问题,业务中真实可复用的组件有,但是没用想象中那么多。我仔细看了一下components里面的组件多达到57个,这些组件重设计都具有复用性;但真正高频使用的多半为常用组件,但是我们的设计在引用的第三方库没找到一样的风格这种组件的复用性较高。另一一类是业务中多个地方都会使用的类似数据结构对应的组件,但不超过10个。但使用的第三方组件库和自定义风格组件以及常复用业务组件还是解决了一定的复用问题。减少复制粘贴,修改时候也可以在同一个地方修改。这个角度上讲是提高效率和可维护,解决这种问题的思路如果不局限于框架中又有没有什么其他的实践方式呢?我觉得vue在这个方面是提供一个方式,自己封装一个一个的函数,然后引用地方标注引入或者替换也能达到同样效果

u=2401612563,2105452038&fm=26&fmt=auto.webp

  1. vue的便利还有数据驱动思想。通过数据和模板的绑定,监听数据的变化而对所对应的数据区域进行局部更新。这种思路相较于以前的开发模式可以大幅度的减少开发者对DOM的操作,只需要专注于数据绑定和数据更新。
    u=957073364,1048354877&fm=26&fmt=auto.webp
  2. vue之痛。之前做过一个东西,一次性返回5000条列表数据,组件渲染和销毁时都需要大量时间造成严重卡顿,当时协调后端分页无果,硬着头皮分析出产生卡顿的原因

    进入页面上,会对5000条数据都执行defineReactive方法,离开页面时候也会大量执行解除绑定的方法

    解决的策略:

    • 重新设计该列表组件,每次只渲染50-200条(computed);计算出当前渲染的条数和应该滚动到的位置,缓存几十条,预加载几十条
    • 不使用vue策略,直接使用纯js动态处理,以达到不对数据遍历绑定监听的而方式。vue组件中,数据存储放在data内部直接this内,而不是return 中的data对象;获取到值后顺便调用渲染函数
    export default {
     data() {
         this.bigDataList = [];
         return {}
     },
     methods: {
         getBigDataList() {
             getData().then(data => {
                 this.bigDataList = data;
                 this.render()
             })
         },
         render() {
             const el = this.$refs.bigdataRef;
             // 移除原有节点,创建新的节点,最后统一挂载
         }
     }
    }

经此一役,我不否定原生js存在的意义,也看到vue的一些局限。vue是解决很多问题,但也不是解决所有问题。技术存在的根本是为了解决某些场景问题

我的知识体系简述

image.png

  • js核心语言精粹及语言特性
  • ES6+拓展
  • VUE全家桶及源码原理
  • 常用的设计模式
  • 工程化
  • http协议

u=3480629088,2629367094&fm=26&fmt=auto.webp

JavaScript

u=2898714478,1201627282&fm=26&fmt=auto.webp

  1. 事件循环
  2. 闭包
  3. 函数调用特性
  4. 执行上下文
  5. DOM事件机制
  6. 垃圾回收机制

Vue

src=http___pic4.zhimg.com_v2-cef492aa2c7be6261b22d60a3e806789_r.jpg&refer=http___pic4.zhimg.jpg

看后面的内容可能比较偏向于原理,我默认阁下是已经将vue的api用得滚瓜烂熟了,不然可能看个热闹。

这个思路可能更有助于学习

  • 结构化程序设计

    • 基本结构

      • 顺序
      • 选择
      • 循环
    • 设计方法

      • 自顶向下
      • 逐步细化
      • 模块化
vue = 数据侦测 + 虚拟DOM + 模板编译 + 指令 + 生命周期 + 内部api + 全局api

模板编译

我们在写vue的时候,template中内容就是模板。我对vue2.6版本比较熟一些。这个版本会将模板编译成render函数后再渲染。大致流程如下

template => parse(ast) => optimizer(静态节点,patch) => generate => render函数 

parse函数中调用parseHTML,这个函数主要接受template,配置参数,和一些生命周期

  • start 收集抽象语法树节点
  • end
  • comment 注释处理
  • chars 文本处理
function parse() {
    parseHTML(html, {
        start(){},
        end(){},
        chars(){},
        comment(){}
    })
}

parseText 里面会处理文本和文本表达式。

生产代码 genElement


function generate(ast, options) {
    const state =generateState(options);
    const code = genElement(ast, state);
    return {
        render: `with(this){return ${code}}`,
        ...
    }
}

function genElement() {
    // 顺序:static => once => for => if => children => slot => component
}


虚拟dom

为了减少dom操作的开销,使用js对象描述dom,该js对象就是虚拟dom。也就是对应源码vNode的实例。

本质上是用js的计算性能换取真实dom的操作性能。

简单实例

{
    tag: "",
    data: {},
    children: [],
    text: "",
    context: "",  // 组件作用域
    componentOptions: "",  // 组件参数
    // 实例, key,函数组件content 函数组件参数等  ...
}

vNode类型

  • 注释节点
  • 文本节点
  • 元素节点
  • 组件节点
  • 函数式组件节点
  • 克隆节点

diff 算法 patch => "patchVnode"

对比新旧vNode,找出差异,只更新差异。

patch 只做了三件事

  • 创建节点
  • 删除节点
  • 更新节点属性

能被创建且插入dom的节点

  • 元素节点
  • 文本节点
  • 注释节点
patchVnode
  1. 完全一样
  2. 都是静态节点
  3. 判断text [更新]
  4. 判断都有子节点 => updateChildren [创建,删除]
  5. 新的vNode有子节点 [创建]
  6. 旧的有子节点

虚拟dom的优化 updateChildren

本质上是解决新旧两个数组对比的问题,最简单、最糟糕的情况是双重循环;这个地方的优化主要是避免双重循环。

定义新旧首尾4个索引值

  1. 通过齐头比较
  2. 通过齐尾比较
  3. 通过新的第一个去遍历旧的所有
  4. 通过旧的第一个遍历新的所有
  5. 双重循环

大部分情况页面不大范围更新,这个时候前面的简单判断就可以避免大部分性能问题。

生命周期

初始化

合并参数,初始化事件,初始化渲染

  • beforeCreate

初始化 injections 注入
初始化 state
初始化 initProvide 提供

  • created

编译,更新

  • beforeUpdate
  • updated

挂载

  • beforeMount
  • mounted

销毁

  • beforeDestroy
  • destroyed

几个不常用的生命周期

  • activated ,组件激活( keep-alive)
  • deactivated, 组件已停用( keep-alive)
  • errorCaptured, 错误捕获

VueRouter

src=http___pic1.zhimg.com_v2-a3d096828c34f29fe237c03b9fa9302d_1200x500.jpg&refer=http___pic1.zhimg.jpg

vue-router是vue单页应用的路由管理器。

VUEX

src=http___upload-images.jianshu.io_upload_images_19871305-953e13a9c8113f1c.jpg&refer=http___upload-images.jianshu.jpg

vuex是vue全家桶中的状态管理器,可用于缓存数据,以及组件之间的通讯。特点是数据变化可预测,数据响应式,递归模块开发。

image.png

组成和用法

  1. state 用于数据存储
  2. getters 基于state进行数据派生
  3. mutations 唯一用于修改state的方式
  4. action 处理异步情况,在其函数内获取异步数据后调用mutations内的方法
  5. modules 用于处理嵌套子模块,分割比较大的项目的数据组织

另外vuex还提供 mapState mapGetters mapMutations mapActions 来在组件中快速映射出vuex中的属性和方法。createNamespacedHelpers 也是一个节省代码的工具,在modules里面如果启动了命名空间,mapper的时候也会有很长的命名空间参数,这个时候以命名空间为参数 调用 createNamespacedHelpers 方法生成的派生函数可以减少大量代码。

getters中的属性如果派生出来需要双向绑定v-modal需要在computed 中 get,set【commit】

export default {
    computed : {
        message: {
            get() {
                return this.$store.state.obj.message
            },
            set (value) {
                this.$store.commit('updateMessage', value)
            }
        }
    }
}

严格模式 strict,通常只在开发环境开启,运行环境关闭,主要是为了避免直接修改state的问题,通过开发过程中非法操作警告,使编码本身符合 “可信单一数据源”的方式,然后生产环境上取消这种检测达到相同目的。

源码结构简述

vuex的边界和特殊处理策略

u=822340110,210495907&fm=15&fmt=auto.webp

设计模式

HTTP协议

工程化

  • 脚手架
  • 组件库
  • 内网包管理仓库
  • 快速构建

有意思的业务场景

设计四大基本原则

  • 对比
  • 重复
  • 对齐
  • 亲密度

常见代码结构组织

前端工程师的js代码一直是一个充满惊喜的东西。工作这几年我看到了很多千奇古怪的代码组织方式。下面是一些我觉得还不错的代码组织方式。

// 类式结构
class Sub {
    constructor(){
        this.list = []
    }
    add() {}
    remove() {}
}
// c式结构
function main () {
    init()
    const data = execute()
    render(data)
}
function init() {}
function execute() {}
function render() {}
// 字面量组合结构

const obj = {
    utils: {
        version: "",
        flat () {}
    },
    api: {
        getDataList () {}
    },
    store: {
        save(key, value){},
        get(key) {},
        remove() {}
        clear() {}
    }
}
/** Data, Params , Callback 式
  * 这种结构通常用于处理异步,或者对数据有差异化处理的情况
*/
function fn(data, params, callback) {

}


fn(data, params, () => {
    // 22
})
// module 式
let data
class Obj {}
function fn () {}
function cn() {}


export {
    fn,
    cn
}
export default Obj

性能优化,效率提升

性能优化是一个不可忽视的问题。对性能因素进行简单的做个分类。

运行时

  • 服务器生成数据

    • 生成得数据也可以在服务器端缓存,一段时间内不做计算或者数据库查询。
  • 网络传输过程

    • 开启gzip压缩
    
    gzip on;                        // 开启压缩
    gzip_min_length 1k;             // 超过1k才压缩,建议设置成 大于1k,否则越压越大
    gzip_buffers 4 16k;             // 设置缓存压缩结果大小, ‘4 16k’表示以16k*4为单位
    gzip_comp_level 5;              // 压缩等级,[1-9]越小压缩效果越差,但是越大处理越慢
    gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;                     // 指定压缩的资源类型
    
    • 304缓存,减少从服务端返回客户端的数据
    • 代理服务器缓存
    • 开启cdn
    • 减少文件体积,代码压缩,图片压缩

      • UglifyPlugin
      • MiniCssExtractPlugin
      • HtmlWebpackPlugin
    • vue组件 适当的合并太小的文件 webpackchunkname,或者拆分太大的文件(() => import)
    • 合并多张小图片雪碧图
    • 对于静态资源可以使用缓存,Cache-Control

cdn加速的原理是:

  1. 浏览器要请求域名服务器将解析为IP地址
  2. 本地 DNS 依次向根服务器、顶级域名服务器、权限服务器发出请求,得到全局负载均衡系统(GSLB)的 IP 地址。
  3. 本地 DNS 再向 GSLB 发出请求,GSLB 的主要功能是根据本地 DNS 的 IP 地址判断用户的位置,筛选出距离用户较近的本地负载均衡系统(SLB),并将该 SLB 的 IP 地址作为结果返回给本地 DNS。
  4. 本地 DNS 将 SLB 的 IP 地址发回给浏览器,浏览器向 SLB 发出请求。
  5. SLB 根据浏览器请求的资源和地址,选出最优的缓存服务器发回给浏览器。
  6. 浏览器再根据 SLB 发回的地址重定向到缓存服务器。
  7. 如果缓存服务器有浏览器需要的资源,就将资源发回给浏览器。如果没有,就向源服务器请求资源,再发给浏览器并缓存在本地
  • 客户端执行渲染

    • 数据量巨大处理策略

      • 虚列表技术

        1. 窗口容器中设置滚动事件监听
        2. 列表容器,更具数据数量和数据高度设置高度
        3. 记录滚动过程容器scrollTop
        4. 根据 scrollTop计算列表容器的paddingTop值
        5. 根据scrollTop和列表项高度计算渲染索引值 index
        6. 根据 index data max 计算当前所需渲染数据 showData
      • 分片渲染 FramRender

        每次requestAnimateFrame 执行的时候,进行一部分渲染,直到全部完成渲染
    • 超过1000条的树形结构数据处理(用循环代替递归)

      • list2tree
      • tree2list

开发阶段

  • 构建速度
  • 打包速度

一般项目代码量变大过后无论是打包还是构建的速度都会变慢,因此需要优化,大致思路。

  • 指定npm包镜像地址提升下载包的速度,优先级: 公司内网 > 国内镜像源地址 > 国外镜像源地址

    npm config set registry https://registry.npm.taobao.org  // 设置为淘宝镜像源
    npm config get registry // 查看设置的镜像源地址
  • 部分包不参与打包,使用src引入

    1

张仪ranck
410 声望9 粉丝