主要思路:
- Vue 代码层面的优化;
- webpack 配置层面的优化;
- 基础的 Web 技术层面的优化。
- 非框架代码优化
- 手段:是动态的向DOM树内添加或者删除DOM元素;是通过设置DOM元素的display样式属性控制显隐;
- 编译过程:切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件;只是简单的基于css切换;
- 编译条件:是惰性的,如果初始条件为假,则什么也不做;只有在条件第一次变为真时才开始局部编译(编译被缓存?编译被缓存后,然后再切换的时候进行局部卸载);
是在任何条件下(首次条件是否为真)都被编译,然后被缓存,而且DOM元素保留; - 性能消耗:有更高的切换消耗;有更高的初始渲染消耗;
是具有缓存的,这就意味着只要计算属性的依赖没有进行相应的数据更新,那么会直接从缓存中获取值,多次访问都会返回之前的计算结果
(1)v-for 遍历必须为 item 添加 key
在列表数据进行遍历渲染时,需要为每一项 item 设置唯一 key 值,方便 Vue.js 内部机制精准找到该条列表数据。当 state 更新时,新的状态值和旧的状态值对比,较快地定位到 diff 。
(2)v-for 遍历避免同时使用 v-if
v-for 比 v-if 优先级高,如果每一次都需要遍历整个数组,将会影响速度,尤其是当之需要渲染很小一部分的时候,必要情况下应该替换成 computed 属性。
Vue 会通过 Object.defineProperty 对数据进行劫持,来实现视图响应数据的变化,然而有些时候我们的组件就是纯粹的数据展示,不会有任何改变,我们就不需要 Vue 来劫持我们的数据,在大量数据展示的情况下,这能够很明显的减少组件初始化的时间,那如何禁止 Vue 劫持我们的数据呢?可以通过 Object.freeze 方法来冻结一个对象,一旦被冻结的对象就再也不能被修改了。
Vue 组件销毁时,会自动清理它与其它实例的连接,解绑它的全部指令及事件监听器,但是仅限于组件本身的事件。 如果在 js 内使用 addEventListene 等方式是不会自动销毁的,我们需要在组件销毁时手动移除这些事件的监听,以免造成内存泄露,如:
这样使用 webpcak 打包后的文件很大,当进入首页时,加载的资源过多,页面会出现白屏的情况,不利于用户体验。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应的组件,这样就更加高效了。这样会大大提高首屏显示的速度,但是可能其他的页面的速度就会降下来。
小的图片转化为 base64 格式;对有些较大的图片资源,在请求资源的时候,加载会很慢,我们可以用 image-webpack-loader来压缩图片
将每个页面的第三方库和公共模块提取出来
Vue 项目中用到的分析工具:webpack-bundle-analyzer 。
压缩组件通过减少 HTTP 请求产生的响应包的大小,从而降低传输时间的方式来提高性能。从 HTTP1.1 开始,Web 客户端可以通过 HTTP 请求中的 头来标识对压缩的支持:
当浏览器通过代理来发送请求时,有可能出现浏览器期望接受的压缩后内容和实际接收到的不一致的情况。解决这一问题的方法是在 Web 服务器的响应中添加 Vary 头。Web 服务器可以告诉代理根据一个或多个请求头来改变缓存的响应。由于压缩的决定是基于 请求头的,因此需要在服务器的 Vary 响应头中包含
目前大约 90% 的通过浏览器进行的网络通信都需要使用 gzip,这使得服务端和客户端的对等性变得额外重要。无论是客户端还是服务端发送错误,都会造成页面被破坏。避免错误的一种方式是采用『浏览器白名单』方式,即只为经过证实支持压缩的浏览器提供压缩内容,但是当代理缓存加进来以后,处理边缘情形浏览器将变得更加复杂。另一种方式是使用 或 头来禁用代理缓存。此种方式会为所有浏览器禁用代理缓存,从而增加带宽开销。如何平衡压缩和代理支持需要在加快响应时间、减小带宽开销和边缘情形浏览器缺陷之间进行权衡。
- 如果网站的用户很少,并且他们处于一个小圈子中,边缘情形浏览器不需要太多关注,可以压缩内容并使用 。
- 如果更注重带宽开销,可以和前一种情形一样,压缩内容并使用 。
- 如果网站拥有大量的、多变的用户群,能够应付较高的带宽开销,并且享有高质量的声誉,需要压缩内容并使用 ( Google 和 Yahoo 都使用这种方式)
减少http的请求次数,将多个请求合并成同一个,减少http的开销。
在优化 Web 性能的方法中,减少重绘、重排是一种很好的优化方式。减少重绘、重排措施:
- 使用 class 操作样式,而不是频繁操作 style
- 避免使用 table 布局
- 批量dom 操作,例如 createdocumentFragment,或者使用框架,例如 React
- Debounce window resize 事件
- 对 dom 属性的读写要分离
- will-change: transform 做优化
关注性能的前端工程师希望页面被逐步渲染,这时因为,我们希望浏览器尽早渲染获取到的任何内容。这对大页面和网速慢的用户很重要。给用户视觉反馈,比如进度条的重要性已经被大量研究和记录。在我们的情况中,HTML 页面就是进度条。当浏览器逐步加载页面头部,导航条,logo 等等,这些都是给等待页面的用户的视觉反馈。这优化了整体用户体验。
把样式表放在文档底部的问题是它阻止了许多浏览器的逐步渲染,包括 IE。这些浏览器阻止渲染来避免在样式更改时需要重绘页面元素。所以用户会卡在白屏。
HTML 规范 清楚表明样式应该在 里。
脚本会阻塞并行下载,HTTP/1.1 官方文档建议浏览器每个主机名下并行下载的组件数不要超过两个,如果图片来自多个域名,并行下载的数量就可以超过两个。如果脚本正在下载,浏览器就不开始任何其它下载任务,即使是在不同域名下的。
有时候,并不容易把脚本移动到底部。举个例子,如果脚本是用 document.write 插入到页面内容中的,就没办法再往下移了。还可能存在作用域问题,在多数情况下,这些问题都是可以解决的。
一个常见的建议是用推迟(deferred)脚本,有 DEFER 属性的脚本意味着不能含有 document.write,并且提示浏览器告诉他们可以继续渲染。不幸的是,Firefox 不支持 DEFER 属性。在 IE 中,脚本可能被推迟,但不尽如人意。如果脚本可以推迟,我们就可以把它放到页面底部,页面就可以更快地载入。
详细见另一篇文章👉:有关前端性能优化—DNS解析优化的方法?
用户输入 URL 以后,浏览器首先要查询域名(example.com)对应服务器的 IP 地址,这个操作一般需要耗费 20-120 毫秒时间。DNS 查询完成之前,浏览器无法从服务器下载任何数据。
基于性能考虑,ISP、局域网、操作系统、浏览器都会有相应的 DNS 缓存机制。
IE 缓存 30 分钟,可以通过注册表中 DnsCacheTimeout 项设置; Firefox 缓存 1 分钟,通过
network.dnsCacheExpiration 配置; Chrome 缓存 1 分钟,通过
chrome://net-internals/#dns 配置。
另外需要注意的是这里有一个矛盾,减少不同的域名可减少 DNS 查找,同时也减少了页面下载资源文件的并发量。也就是说,虽然避免 DNS 查找削减了响应时间,但是减少并行下载数量却增加了响应时间。原则是把组件分散在 2~4 个域名下,控制好数量,这是同时减少 DNS 查找和允许并发下载的折中方案。