spa单页应用-首屏性能优化-进阶版(1s内)
点赞在看,养成习惯 (~ ̄▽ ̄)~
需先了解一下初级版
初级版(我的另一篇):juejin.cn/post/699685…
初级版存在的问题?
初级版主要是解决了:接口延迟,导致路由渲染延迟,进而导致页面渲染延迟的问题。
但是:在渲染首屏内容之前,还解析了很多资源:比如(常见) vue / vue-router / vuex / ui组件库 等 (此处暂时以vue为例,react也是类似的)
其实我们的优化空间还有:
方案一
- 所有资源都不加载,我先渲染静态部分(比如整个页面的结构,布局,样式,色块等),首屏东西出来后,在加载其他 (方案一的优化思路类似骨架屏)
方案二
- 只需加载一个框架资源vue或react(不加载router等),首屏渲染出来后,在加载其他
两个方案效果对比
两个方法都有尝试过,此处我简单作个结论:
-
两种方法都可以用,方案一的首屏时间会更快,但是对代码的结构改动较大,因为要写原生代码(写在入口的index.html文件内,其他的script标签都放页尾)(方案一除了类似骨架屏,也类似服务端渲染优化思路)
-
方案二会比方案一稍微慢一点,因为多加载了一个框架资源vue或react。但方案二对代码结构改动较小,更容易实现
方案二的实现技巧
背景:有小伙伴问我,组件库好实现延迟加载,但是延迟加载router和store实现不了
所以,以下主要是方案二的实现介绍:
- 此处以vue2为例(vue3的按需加载比vue2要做的更好,所以vue3实现还要更容易。react也是类似思路)
首先以一个基础项目举例,直接vue-cli出来的简单项目(vue2):cli.vuejs.org/zh/guide/cr…
目录结构,就列几个主要文件
src
lazyApp.vue
App.vue
main.js
vue.config.js
首先 vue.config.js
// vue.config.js
module.exports = {
runtimeCompiler: true // 配置这个,目的是为了 支持动态解析template (有兴趣了解原理的话,可以看我另一篇: https://juejin.cn/post/7043991342166310942)
}
以下是main.js ,cli出来的原样,几乎不用动
// main.js
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
以下是app.vue
-
以下实现了路由vue-router的按需加载 (要安装依赖
npm i -S vue-router@3) -
原理类似是 在#app里面在套了一个#lazyApp,目的是先渲染 #app的内容,让首屏更快的渲染出来,在加载其他资源和内容(其他内容放在 #lazyApp 内)
<template>
<div id="app">
<h1>我是首屏最先出来的内容</h1>
<h1>我是首屏最先出来的内容</h1>
<h1>我是首屏最先出来的内容</h1>
<h1>我是首屏最先出来的内容</h1>
<div id="lazyApp"></div> // 此处放 懒加载的内容
</div>
</template>
<script>
import Vue from 'vue'
import lazyApp from './lazyApp.vue'
export default {
name: 'App',
mounted () {
import(/* webpackChunkName: 'vue--router' */'vue-router').then(VueRouter => {
VueRouter = VueRouter.default
Vue.use(VueRouter)
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
const CCC = { template: '<div>ccc</div>' }
const router = new VueRouter({
routes: [
{ path: '/a', component: Foo },
{ path: '/b', component: Bar },
{ path: '/c', component: CCC },
]
})
new Vue({
render: h => h(lazyApp),
router
}).$mount('#lazyApp') // 会把 <div id="lazyApp"></div> 这个标签替成 lazyApp.vue
})
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
a {
margin: 10px;
}
</style>
以下是 lazyApp.vue (可以理解为嵌套的 #app)
<template>
<div>
<span>我是菜单: </span>
<a href="/#/a">a</a>
<a href="/#/b">b</a>
<a href="/#/c">c</a>
<router-view></router-view>
<h3>我是lazyApp的内容</h3>
<h3>我是lazyApp的内容</h3>
<h3>我是lazyApp的内容</h3>
<h3>我是lazyApp的内容</h3>
</div>
</template>
加载的效果
- 图片内有3个色块,可以按色块和文字备注,以及右侧network面板搭配,来更好的理解优化效果(先加载 首屏 -> 在其他)
总结
优化方案一
- 所有资源都不加载,我先渲染静态部分(比如整个页面的结构,布局,样式,色块等),首屏东西出来后,在加载其他 (方案一的优化思路类似骨架屏)
优化方案二
- 只需加载一个框架资源vue或react(不加载router等),首屏渲染出来后,在加载其他
两个方案的对比:
-
两种方法都很有效,方案一的首屏时间会更快,但是对代码的结构改动较大,因为要写原生代码(写在入口的index.html文件内,其他的script标签都放页尾)(方案一的优化思路 类似骨架屏,也类似服务端渲染)
-
方案二会比方案一稍微慢一点,因为多加载了一个框架资源vue或react。但方案二对代码结构改动较小,更容易实现
优化后的效果:
- 首屏正常可以优化到1秒内(正常网速和网络情况)
码字不易,点赞鼓励!