本篇内容介绍了“优化Web应用程序性能的方案及其优缺点说明”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
创新互联成立于2013年,先为公安等服务建站,公安等地企业,进行企业商务咨询服务。为公安企业网站制作PC+手机+微官网三网同步一站式服务解决您的所有建站问题。
Chrome Corverage 分析代码覆盖率
在讲解这些机制前,先来谈一个 Chrome 工具 Corverage。该工具可以帮助查找在当前页面使用或者未使用的 JavaScript 和 CSS 代码。
工具的打开流程为:
打开浏览器控制台 console
ctrl+shift+p 打开命令窗口
在命令窗口输入 show Coverage 显示选项卡
webpackjs
其中如果想要查询页面加载时候使用的代码,请点击 reload button
如果您想查看与页面交互后使用的代码,请点击record buton
这里以淘宝网为例子,介绍一下如何使用
上面两张分别为 reload 与 record 点击后的分析。
其中从左到右分别为
所需要的资源 URL
资源中包含的 js 与 css
总资源大小
当前未使用的资源大小
左下角有一份总述。说明在当前页面加载的资源大小以及没有使用的百分比。可以看到淘宝网对于首页代码的未使用率仅仅只有 36%。
介绍该功能的目的并不是要求各位重构代码库以便于每个页面仅仅只包含所需的 js 与 css。这个是难以做到的甚至是不可能的。但是这种指标可以提升我们对当前项目的认知以便于性能提升。
提升代码覆盖率的收益是所有性能优化机制中最高的,这意味着可以加载更少的代码,执行更少的代码,消耗更少的资源,缓存更少的资源。
webpack externals 获取外部 cdn 资源
一般来说,我们基本上都会使用 Vue,React 以及相对应的组件库来搭建 SPA 单页面项目。但是在构建时候,把这些框架代码直接打包到项目中,并非是一个十分明智的选择。
我们可以直接在项目的 index.html 中添加如下代码
然后可以在 webpack.config.js 中这样配置
module.exports = { //... externals: { 'vue': 'Vue', 'vue-router': 'VueRouter', } };
webpack externals 的作用是 不会在构建时将 Vue 打包到最终项目中去,而是在运行时获取这些外部依赖项。这对于项目初期没有实力搭建自身而又需要使用 CDN 服务的团队有着不错的效果。
原理
这些项目被打包成为第三方库的时候,同时还会以全局变量的形式导出。从而可以直接在浏览器的 window 对象上得到与使用。即是
window.Vue // ƒ bn(t){this._init(t)}
这也就是为什么我们直接可以在 html 页面中直接使用
{{ message }}// Vue 就是 挂载到 window 上的,所以可以直接在页面使用 var app = new Vue({ el: '#app', data: { message: 'Hello Vue!' } })
此时我们可以通过 webpack Authoring Libraries 来了解如何利用 webpack 开发第三方包。
优势与缺陷
优势
对于这种既无法进行代码分割又无法进行 Tree Shaking 的依赖库而言,把这些需求的依赖库放置到公用 cdn 中,收益是非常大的。
缺陷
对于类似 Vue React 此类库而言,CDN 服务出现问题意味着完全无法使用项目。需要经常浏览所使用 CDN 服务商的公告(不再提供服务等公告),以及在代码中添加类似的出错弥补方案。
webpack dynamic import 提升代码覆盖率
我们可以利用 webpack 动态导入,可以在需要利用代码时候调用 getComponent。在此之前,需要对 webpack 进行配置。具体参考 webpack dynamic-imports。
在配置完成之后,我们就可以写如下代码。
async function getComponent() { const element = document.createElement('div'); /** webpackChunkName,相同的名称会打包到一个 chunk 中 */ const { default: _ } = await import(/* webpackChunkName: "lodash" */ 'lodash'); element.innerHTML = _.join(['Hello', 'webpack'], ' '); return element; } getComponent().then(component => { document.body.appendChild(component); });
优势与缺陷
优势
通过动态导入配置,可以搞定多个 chunk,在需要时候才会加载而后执行。对于该用户不会使用的资源(路由控制,权限控制)不会进行加载,从而直接提升了代码的覆盖率。
缺陷
Tree Shaking,可以理解为死代码消除,即不需要的代码不进行构建与打包。但当我们使用动态导入时候,无法使用 Tree Shaking 优化,因为两者直接按存在着兼容性问题。因为 webpack 无法假设用户如何使用动态导入的情况。
基础代码X 模块A 模块B ----------------------------------- 业务代码A 业务代码B 业务代码...
当在业务中使用多个异步块时后,业务代码A 需求 模块A,业务代码 B 需求 模块B,但是 webpack 无法去假设用户在代码中 A 与 B 这两个模块在同一时间是互斥还是互补。所以必然会假设同时可以加载模块 A 与 B,此时基础代码 X 出现两个导出状态,这个是做不到的!从这方面来说,动态导入和 Tree Shaking 很难兼容。具体可以参考 Document why tree shaking is not performed on async chunks 。
当然,利用动态导入,也会有一定的性能降低,毕竟一个是本地函数调用,另一个涉及网络请求与编译。但是与其说这是一种缺陷,倒不如说是一种决策。究竟是哪一种对自身的项目帮助更大?
使用 loadjs 来辅助加载第三方 cdn 资源
在普通的业务代码我们可以使用动态导入,在当今的前端项目中,总有一些库是我们必需而又使用率很低的库,比如在只会在统计模块出现的 ECharts 数据图表库,或者只会在文档或者网页编辑时候出现的富文本编辑器库。
对于这些苦库其实我们可以使用页面或组件挂载时候 loadjs 加载。因为使用动态导入这些第三方库没有 Tree shaking 增强,所以其实效果差不多,但是 loadjs 可以去取公用 CDN 资源。具体可以参考 github loadjs 来进行使用。因为该库较为简单,这里暂时就不进行深入探讨。
使用 output.publicPath 托管代码
因为无论是使用 webpack externals 或者 loadjs 来使用公用 cdn 都是一种折衷方案。如果公司可以花钱购买 oss + cdn 服务的话,就可以直接将打包的资源托管上去。
module.exports = { //... output: { // 每个块的前缀 publicPath: 'https://xx/', chunkFilename: '[id].chunk.js' } }; // 此时打包出来的数据前缀会变为
此时业务服务器仅仅只需要加载 index.html。
利用 prefetch 在空缺时间加载资源
如果不需要在浏览器的首屏中使用脚本。可以利用浏览器新增的 prefetch 延时获取脚本。
下面这段代码告诉浏览器,echarts 将会在未来某个导航或者功能中要使用到,但是资源的下载顺序权重比较低。也就是说prefetch通常用于加速下一次导航。被标记为 prefetch 的资源,将会被浏览器在空闲时间加载。
该功能也适用于 html 以及 css 资源的预请求。
利用 instant.page 来提前加载资源
instant.page 是一个较新的功能库,该库小而美。并且无侵入式。 只要在项目的