Web应用性能优化解决方案总结
时间:2023-03-13 09:04:31
科技观察
在开发Web应用时,性能是一个必不可少的话题。大部分前端优化机制已经集成到前端打包工具webpack中。当然,仍然有一些有趣的机制可以帮助Web应用程序提高性能。这里我们会讲到如何优化web应用程序的一些机制,也会讲到这些机制背后的原理。ChromeCorverage分析代码覆盖率在讲解这些机制之前,先说一个Chrome工具Corverage。此工具可帮助查找在当前页面上使用或未使用的JavaScript和CSS代码。打开工具的过程是:打开浏览器控制台ctrl+shift+p打开命令窗口在命令窗口输入showCoverage并显示webpackjs选项卡如果要查询页面加载时使用的代码,请点击reloadbutton如果想查看与页面交互后使用的代码,请点击record按钮这里以淘宝为例,分别介绍点击reload和record后如何使用上面的两个解析。其中,从左到右分别是需要的资源URL资源中包含的js和css资源总大小,以及当前未使用的资源大小。左下角有总结。指示当前页面上加载的资源大小和未使用的百分比。可以看出,淘宝首页代码的未使用率仅为36%。引入这个特性的目的并不是要你重构你的代码库,让每个页面只包含需要的js和css。这是困难的,甚至是不可能的。但是这种指标可以提高我们对当前项目的了解,从而提高绩效。提高代码覆盖率的好处是所有性能优化机制中最高的,这意味着可以加载更少的代码,执行更少的代码,消耗更少的资源,缓存更少的资源。webpackexternals获取外部CDN资源一般来说,我们构建SPA单页项目基本都是使用Vue、React以及相应的组件库。但是在构建的时候,将这些框架代码直接打包到项目中并不是一个非常明智的选择。我们可以直接在项目的index.html中加入如下代码然后你可以像这样在webpack.config.js中配置module.exports={//...externals:{'vue':'Vue','vue-router':'VueRouter',}};webpackexternals的作用并不是Vue会在构建时打包到最终的项目中,而是这些外部依赖会在运行时被拾取。这对于项目初期没有实力自建,但又需要使用CDN服务的团队有很好的效果。原理这些项目在打包成第三方库的时候,也会以全局变量的形式导出。因此,可以直接在浏览器的window对象上获取和使用。就是window.Vue//?bn(t){this._init(t)},这就是为什么我们可以在html页面Vue中直接使用{{message}}
//挂载在window上,所以可以直接在页面上使用varapp=newVue({el:'#app',data:{message:'HelloVue!'}})。至此,我们就可以学习如何使用webpackAuthoringLibraries使用webpack开发第三方包了。优缺点Advantages对于这种既不能进行codesplitting也不能进行TreeShaking的依赖库,将这些需要的依赖库放在一个公共的CDN中是非常有好处的。Bugs对于像VueReact这样的库,CDN服务出现问题意味着项目根本无法使用。需要经常浏览所使用的CDN服务商的公告(比如不再提供服务的公告),在代码中加入类似的错误补偿方案。webpack动态导入提高代码覆盖率我们可以使用webpack动态导入,在需要使用代码的时候调用getComponent。在此之前,需要配置webpack。有关详细信息,请参阅webpack动态导入。配置完成后,我们就可以编写如下代码了。asyncfunctiongetComponent(){constelement=document.createElement('div');/**webpackChunkName,同名会打包成一个chunk*/const{default:_}=awaitimport(/*webpackChunkName:"lodash"*/'lodash');element.innerHTML=_.join(['Hello','webpack'],'');returnelement;}getComponent().then(component=>{document.body.appendChild(component);});优点和缺陷优点通过动态导入配置,可以处理多个chunk,在需要的时候加载执行。用户不会使用的资源(路由控制、权限控制)不会被加载,直接提高了代码的覆盖率。DefectTreeShaking可以理解为deadcodeelimination,即不构建和打包不需要的代码。但是当我们使用动态导入的时候,就不能使用TreeShaking优化了,因为这两者之间存在兼容性问题。因为webpack无法假设用户如何使用动态导入。BasicCodeXModuleAModuleB--------------------------------BusinessCodeABusinessCodeBBusinessCode...当业务中使用多个异步块时,业务代码A需要模块A,业务代码B需要模块B,但是webpack不能假设用户代码中的A和B两个模块在交互的时候同时排斥或互补。因此,不可避免地假设模块A和B可以同时加载。此时基本代码X有两个出口状态。这是不可能的!从这个角度看,dynamicimport和TreeShaking很难兼容。详情请参考文档whytreeshakingisnotperformedonasyncchunks。当然,使用动态导入也会在一定程度上降低性能。毕竟一个是本地函数调用,一个涉及到网络请求和编译。但这更像是一个决定而不是缺陷。哪个对自己的项目更有帮助?使用loadjs辅助加载第三方CDN资源。我们可以在普通的业务代码中使用动态导入。在如今的前端项目中,总有一些我们需要但使用率很低的库。比如只在统计模块中出现的ECharts数据图表库,或者只有在编辑文档或网页时才会出现的富文本编辑器库。对于这些苦涩的库,我们其实可以在页面或者组件挂载的时候使用loadjs来加载。因为使用动态导入这些第三方库并没有通过Treeshaking增强,效果差不多,但是loadjs可以拉取公共CDN资源。具体可以参考githubloadjs使用。由于该库比较简单,这里不做深入探讨。使用output.publicPath托管代码,因为将公共cdn与webpack外部或loadjs一起使用是一种权衡。如果公司可以花钱购买oss+cdn服务,可以直接托管打包好的资源。module.exports={//...output:{//每个块的前缀publicPath:'https://xx/',chunkFilename:'[id].chunk.js'}};//在此打包时间输出数据的前缀会变成,此时业务服务器只需要加载index.html即可。如果您不需要在浏览器的第一个屏幕中使用脚本,请在空闲时使用预取来加载资产。您可以使用浏览器的新预取来延迟获取脚本。下面这段代码告诉浏览器,以后某个导航或者功能会用到echarts,但是资源的下载顺序有比较低的权重。也就是说,prefetch通常是用来加速下一次导航的。标记为预取的资源将在空闲时由浏览器加载。
该功能同样适用于html和css资源预先请求。使用instant.page提前加载资源instant.page是一个比较新的小而美的特征库。并且非侵入性。只需在项目的