首页 > 代码库 > 进一步优化SPA的首屏打开速度(模块化与懒加载) by 嗡

进一步优化SPA的首屏打开速度(模块化与懒加载) by 嗡

前言

单页应用的好处在于一次载入所有页面资源,利用本地计算能力渲染页面,提高页面切换速度与用户体验。但缺点在于所有页面资源将被一次性下载完,此时封装出来的静态资源包体积较大,使得第一次打开SPA页面时候需要的载入时间较长。

在上一篇文章Angular2 单页应用一些优化总结 中提到的利用压缩、混淆、开启gzip传输后,我们成功将3.5兆的资源包压缩到350k。但是如果SPA应用的页面数进一步增加,100个甚至1000个页面的时候,还是无法避免巨大的首页资源包加载的问题。所以350k的资源包是否还有进一步优化的空间呢?答案是肯定的!

从SPA的特性可以看出,用户在第一次打开页面时,实际上是把整个网站的所有页面都一起下载下来了,但是很多情况下,用户可能并不会访问到所有页面,或者短时间内仅在1~2个页面之间跳转。所以如果可以在第一次仅下载一部分页面,然后在用户需要的时候继续下载其它页面资源的话,就能进一步压缩首页资源包的体积。以下对优化步骤进行讲解。

模块化

模块化的好处

模块化是后期优化的首要步骤,默认的Angular2 spa的项目结构为:应用主程序(main.ts)、根模块(app.module.ts)、根组件(app.component),然后才是其它的组件components。其实说白了就是一个拥有好多组件的单模块应用而已。

通过模块化划分,我们可以将应用按照不同功能或者作用划分为不同模块,这样也使得应用结构更加清晰。比如电商类应用:产品模块、订单模块、用户模块、购物车模块等。

模块的建立方法

step 1 : 创建模块

在app路径下建立一个modules文件夹单独保存模块比较好一些。通过angular-cli的命令构建模块ng g module testmodule 即可。程序会自动建立一个testmodule文件夹,里边有一个testmodule.module.ts

step 2 : 创建组件

在testmodule文件夹上建立components文件夹,同时创建组件ng g component testcomponent 里边包含标准的组件文件(ts, html, css, spec)文件。

step 3 : 创建模块路由

该路由作为模块内部组件路由使用,而不是根路由。创建方法和根路由相同。需要注意的是模块路由的路径是相对于该模块路径的地址
比如:根路径为/app/testmodule/component1 时,模块内定义的路径应该为component1 。 同时将原RouterModule.forRoot(Routes) 改为RouterModule.forChild(Routes)

将原应用的诸多组件按照上面的方法分为不同模块后,就可以进行下一步懒加载了。

懒加载

懒加载路由

在根路由中,将原url与component的关联改为url与loadChild关联即可。比如

//*********原方案
//app.routing.ts
const routes: Routes = [
    {path:‘component1‘, component:Component1}
]

//********新方案
// new app.routing.ts
const routes: Routes = [
    {path:‘testmodule‘, loadChild:‘app/modules/testmodule/testmodule.module#TestModule‘}
]
// testmodule.routing.ts
cost moduleRoutes: Routes = [
    {path:‘component1‘,component1:Component1}
]

这样对于/app/testmodule/component1 地址,应用首先会加载testmodule,然后,由testmodule模块加载component1组件,完成页面载入。

模块加载策略

上文的loadChild 起到了加载模块的作用,仅在用户点击模块下的链接时,程序才开始下载模块对应的js文件,然后再渲染出来。若希望用户在还未点击页面的时候,就从后台预先载入该模块的js,可以进行如下修改:

// app.routing.ts
//原代码
@NgModule({
    imports:[RouterModule.forRoot(routes)]
    exports:[RouterModule]
})
//改为
@NgModule({
    imports:[RouterModule.forRoot(routes), {preloadingStrategy:PreloadAllModules}]
    exports:[RouterModule]
})

这样程序会在首页资源加载完毕后,在后台自动下载其余模块的资源。这样,用户在进入其它模块页面的时候,不需要等待js资源的下载,同时首页打开速度仍然和仅加载首页模块一样快。

需要注意的一点

在根模块的imports声明中,不能引入懒加载模块,否则,会被打包工具打入首页包中,这样懒加载就没有效果了。

效果对比

(非专线网络,请忽略网络实际加载时间~~~~)

模块区分以及懒加载优化前

图中main.js文件保存了所有页面的代码,体积达到134k之大,整个首页js资源总共350k左右。
技术分享

模块区分以及懒加载优化后

由于我在首页仍然保留了4个页面,所以首页包仍然有76.3k,单页缩小了近一半。同时可以看到多出来的x.chunk.js文件,这些就是懒加载的模块(我使用了PreloadAllModules策略,因此会将所有模块下载下来)。
优化前后,页面点击效果完全一样。
技术分享

<script type="text/javascript"> $(function () { $(‘pre.prettyprint code‘).each(function () { var lines = $(this).text().split(‘\n‘).length; var $numbering = $(‘
    ‘).addClass(‘pre-numbering‘).hide(); $(this).addClass(‘has-numbering‘).parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($(‘
  • ‘).text(i)); }; $numbering.fadeIn(1700); }); }); </script>

    进一步优化SPA的首屏打开速度(模块化与懒加载) by 嗡