一、网络请求方面
在网络加载资源方面,相较于app前端页面占劣势,因为很多css、js、img等等要请求获取,而app的文件在打包的时候已经放进安装包了,不需要重新请求。
但是呢,事物都有两面性,重新请求未必全不好,打包静态文件也不一定全好,我们应该从两面性看待问题。
前端页面会进行网络资源请求,意味着加载慢、渲染慢,但同时意味着界面可控性更强,例如想改什么样式,只需要修改对应的css网络资源就好,而app就没有这么灵活了。
如果做好缓存优化处理,前端页面非首次渲染,运行不一定会慢。
1. dns预解析,在head标签中插入以下代码
相关原理参考以下
https://developer.mozilla.org/zh-CN/docs/Controlling_DNS_prefetching
2. 减少http请求数量
这个比较好理解,请求越少,握手建联,挥手断联的次数就越少,也就减轻了服务器对处理http请求的压力。
在实践中,可以针对img做雪碧图,css、js等进行合并处理。
3. 减小请求资源的大小
资源大小和下载速度成反比,这容易理解,资源当然越小下载加载的越开快。资源越小,对服务器带宽资源耗费就小。
在实践中,可以针对img、css、js做压缩处理,以减小其体积大小。
可采用在线网站处理,也可使用自动构建工具处理,如webpack,同时,针对js采用丑化压缩处理后还能在一定程度上提高js的安全性。
4. 静态资源服务器
如果有条件可以将静态资源放在cdn上面,和主站服务分离开,进而可以减小主站服务器的处理和带宽压力。
同时注意尽量不要让cdn域名和主站服务域名相同,可以防止请求携带大量无用的cookie,造成无所谓的传输和带宽浪费。
5. 服务器端渲染(ssr)
利用服务器的高性能来处理页面,前端只起到展示作用。这个点经常用在渲染首页,因为首次进入可能会有一段空白的时间在请求加载资源。
有利就有弊,这种方案虽然渲染很快,主要应用在单页面应用的首页渲染,不能大量使用,大量使用就会造成服务器端性能压力过大,而客户端性能又处于闲置状态,这就失去了一部分前后端分离的意义了。所以还需要平衡处理在哪些地方需要用到这个方法进行优化。
二.交互处理方面
1. 懒加载和预加载
懒加载主要是针对图片而言的,在进入一个含图片的长列表页面时,我们不希望一次过多的(超出屏幕视界)请求图片资源,而是在滚动达到某一个值的时候,再去请求即将出现在视界中的图片。
预加载是不管使用与否,先把资源获取到,放在变量、缓存中,使用的时候直接拿资源就行了。
具体区别和使用场景可以百度查询。
2.事件委托
例如对于长列表的,我们不需要依次为每一项都绑定事件,尤其是动态插入dom的时候,如果忘记给这些动态的dom绑定事件时,往往事与愿违。
这个时候只需要对包裹列表的盒子绑定相关事件,把触发每一项的事件委托到包裹盒子上面即可,既减少工作量,又优化性能。
3.js优化
1)在保证可读性的基础上,尽量使用简洁的代码。
例如if判断 可以优化为三目运算符 进而可以使用&&符号进行短路处理,
这是弱类型语言的特性。
2)多写必要的注释和排版
很多编程人员有这样的习惯,自己不喜欢写注释,拿到别人的代码时又往往希望有注释。很奇怪......
其实这个简单的事情并不麻烦,只是一种好的编程习惯。如果不写注释,不说别人,就是自己写的代码,一段时间之后再去看,可能都需要花费一点时间再去捋当时是怎么想的,这段代码是处理什么等等,更不要说拿到别人的代码了。
当然,只写有必要的注释,没必要的一眼就能看的懂得,就不要做了,徒增工作量和代码体积。
必要的注释和排版并不能对机器阅读友好,但是能增加人对代码的可读性。
3)对象方法
熟悉对象中所有的方法,能让我们更游刃有余的根据场景选择使用哪个方法更合适。
例如我们判断一个元素是否在数组中存在,经常会看到使用indexOf进而通过返回值是否为-1。其实数组有一个includes方法就是专门做这件事的,返回值直接为Boolean值,且性能要比indexOf要高,执行更快。
虽然这种方式产生的效果很微小,但是勿以善小而不为,积少成多,当代码量和运算量大的时候,这些原生方法运算性能的差异也会造成影响。
不要说等我先用劣质的方法实现功能,以后再说优化的事,很多时候我们在写好功能后,就不想在去动代码了,一是嫌麻烦,二是可能就改出了bug。
所以我们尽量保证在第一次的时候就尽可能的优化好。
当然,做到这一点需要我们对原生js很熟。
4)逻辑优化
这个问题就显得很空了,需要自己根据实践经验总结,多执行代码就多消耗性能,这是毋庸置疑的。我们可以改善的是尽量减少无效代码的执行。
例如
//不要老是.啊.的一次又一次去同一个对象中取数据。
let name= this.data.userInfo.name;
let sex = this.data.userInfo.sex;
let age = this.data.userInfo.age;
// 就不能把经常打点调用的对象保存出来啊
let userInfo = this.data.userInfo;
let name= userInfo.name;
let sex = userInfo.sex;
let age = userInfo.age;
// 进而还可以使用es6的解构语法优化
let { name, sex, age } = this.data.userInfo;
再例如嵌套循环的时候怎么优化更好、一系列判断时先判断哪个方面更好等等问题
有很多可以通过优化算法的问题来实现js逻辑执行性能提高,这也要求善于总结工作经验。
5)防抖节流处理
这是个频发应用场景很清晰,又容易被很多开发者忽略的问题。
例如页面滚动、鼠标移动、输入框发起请求等等。
像这种触发频率很高的事件,我们不可能每次都去执行事件处理程序,这样开销会很大。
可百度查找相关用法或参考链接:
https://segmentfault.com/a/1190000018428170
6)异步和同步
js,尤其在es6出现后的js,天生就支持了异步和同步的不同用法,不像其他语言,例如php,需要引入其他类库才能实现异步。
异步和同步的配合使用,能很大程度上改善体验问题。
例如在引入js资源时,如果不需要同步引入的可添加async和defer属性,不会阻塞dom渲染。
编写代码时,有相关依赖关系的写成同步的方式,没有依赖关系的可以做成异步处理。es6中的Promise,以后es7中出现的async/await都是将异步转为同步的优雅处理方式。
4.重绘与回流
此处不做详细解释
三.资源使用
1. 图片资源
同样是图片资源,格式不同所适合的使用场景也不同。
常用jpg、png、svg、webp 等格式
png和png也不一样,区别在于文件大小和所能表现出的色彩丰富度
png8 —— 2^8色 + 支持透明
png24 —— 2^24色 + 不支持透明
png32 —— 2^24色 + 支持透明
jpg体积大小占优势,但清晰度方面会损失。
webp 在苹果设备上支持有问题。
svg 适合用在矢量图,使用场景单一
png支持透明
2.缓存使用
1)文件缓存
这需要服务端去做了,常用的是第一次请求时在响应头中设置一下缓存标志,浏览器会自动判断怎么处理文件。
Cache-Control(http1.1)(优先级大于Expires)
Expires(http1.0)
response etag (会匹配一个字符串的戳)
request If-None-Match(会匹配一个字符串的戳)
response Last-Modified(绝对时间)
request If-Modified-Since(绝对时间)
2.)代码缓存
由于h5中提供了webstorage,本地缓存localStorage中可以存入大约5M的内容,所有有些代码文件如果长期不改变,也可以考虑放在本地缓存中,这样在以后使用时就可以直接拿到。
例如百度的做法
以上就是个人总结的使用过或知道的性能优化方式,如有错误,望请指正。