如果看过我之前的文章,你会知道我在sprite框架的时候,是把应用中的所有页面js文件一次性全部加载,然后再初始化Vue对象的。
在第一次初始化时就将所有的页面和组件准备好,这是典型的单页应用的做法。
这样做的优点:
- 在应用内部切换页面时渲染速度非常快。
- 由多组件构成的复杂页面的渲染效果是整体渲染,而不是分块渲染(比如先出现上面的组件再出现下面的组件)。
这样做的缺点:
- 当应用的规模比较庞大时,在初始化应用时请求所有的js文件会影响应用的加载速度。
- 加载所有的页面,即使用户并不需要访问的页面,这会造成额外的流量消耗。
虽然以目前的网络速度和用户的平均的流量值,这些缺点并不造成太大的影响,尤其是在我们公司写的移动应用基本都是最多几百KB大小的情况下。
但是我还是打算让sprite框架支持页面的按需加载,避免以后出现大型移动应用时影响用户的访问体验。
什么是页面的按需加载呢?
和上面说的方式恰恰相反,应用再初始化时一个页面js文件都不加载,而是当用户访问某个页面的时候,才去加载这个页面的js文件。
这样做的优点:
- 初始化应用时无需加载所有js文件,因此应用的加载速度块。
- 只加载用户访问页面的js文件,节省流量。
这样做的缺点:
- 由于是按需加载需要使用异步加载的方式,因此使得页面的渲染效果无法保证整体渲染,可能会出现分块渲染。
- 虽然应用的初始化速度加快了,但其实时间只是分摊到用户的每一次页面访问上了,这会影响页面切换的速度。
这样一比较下来你会发现,一次性全部加载的缺点正好是按需加载的优点,而按需加载却又无法实现一次性全部加载的优点。
所以最好的方式应该是根据应用的规模大小选择更适合的加载方式,小应用就选择全部加载,这样会使小应用的访问速度变得更快,而特别大型的应用就选择按需加载,这会大大提供应用初始化的速度,并且也能给用户节省流量。
实现可配置的按需加载
既然两种加载方式各有优点,那么做成可配置的就能满足不同情况的需求了。
为了实现可配置的按需加载,我花了一天的时间,调整了框架的代码。主要利用了VueRouter提供的Promise机制和一个用来配置是使用全部加载还是按需加载的全局对象来实现。
在VueRouter的文档中,你可以看到这样描述:(文档地址:VueRouter-懒加载)
这就是说在构造VueRouter所需的routes数组时,可以使用一个返回promise对象的function来替代vue对象,只需要保证promise对象resolve的的值是一个vue对象即可。
于是我写了一个loadComponent函数,用来封装一个vue对象的异步加载函数:
loadComponent函数接收一个vue对象的js文件路径,然后返回一个能够返回promise对象的function来,这个promise对象resolve的的值就是path路径对应的vue对象。
有了loadComponent函数以后,我又写了一个loadPage方法,用来支持sprite框架之前封装的基于xml配置的vue组件加载,代码如下:
利用loadPge方法就可以实现VueRouter的按需加载了。
然后还需要支持全部加载与按需加载两种方式的可配置,我新增了一个全局变量 window.appLoadAsync,具体描述如下:
之后在原有的应用加载的代码基础上,根据这个全局变量进行分支判断:
你会发现在 appLoadAsync 为false时,即全部加载时,应用的初始化函数init是在require了所有页面的js文件的回调中执行的,这是和按需加载方式的唯一区别。这里利用了require的缓存机制,当一个指定路径的js文件被第一次加载之后,第二次进行require时,会返回上一次加载的结果。所以loadPage函数既可以用于按需加载,也可以用于全部加载。