>>分享Web前端开发技术,并对孙卫琴的《精通Vue.js:Web前端开发技术详解》提供技术支持 书籍支持  卫琴直播  品书摘要  在线测试  资源下载  联系我们
发表一个新主题 开启一个新投票 回复文章 您是本文章第 13493 个阅读者 刷新本主题
 * 贴子主题:  前端Vue单页面应用性能优化 回复文章 点赞(0)  收藏  
作者:mary    发表时间:2021-09-05 09:58:33     消息  查看  搜索  好友  邮件  复制  引用

                                                
  作者:Dung

     来源:[恒生LIGHT云社区](https://developer.hs.net/thread/1340)
浏览器渲染步骤:

     1. 渲染引擎解析HTML,生成DOM Tree
2. 解析CSS文件(包括内联和外联样式),生成CSSOM树,并根据DOM树和CSSOM树生成Render Tree
3. 布局Render Tree,确认每个节点在页面中的位置
4. 绘制Render Tree

     Vue 框架通过数据双向绑定和虚拟DOM,帮我们处理了前端开发中最脏最累的 DOM 操作部分。但 Vue 项目是单页面应用,存在着首页加载缓慢的问题,所以我们仍需要去做Vue 项目性能方面的优化,使项目具有更高效的性能、更好的用户体验。本文通过以下三部分组成:

     基础的 Web 技术层面的优化

     webpack 配置层面的优化

     Vue 代码层面的优化。

基础的 Web 技术层面的优化

查找性能瓶颈Chrome Performance

使用方法:

     1. 打开 Chrome 开发者工具,切换到 Performance 面板
2. 点击 Record 开始录制
3. 刷新页面或展开某个节点
4. 点击 Stop 停止录制

     点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

     结果分析:

     Loading:网络通信和HTML解析

     Scripting:JavaScript执行

     Rendering:样式计算和布局,即重排

     Painting:重绘 对应的详细事件    

针对截图中的JavScript执行占时较长,使用如下方式优化

     JS文件加载会阻塞浏览器渲染线程,导致页面展示缓慢的情况

     防止JS影响页面加载下面有三个解决方案

     1. script 放在 body 里(一般是</body> 上面)

     由于 DOM 是自上而下解析的,因此 JS 不会阻塞 DOM 的解析,而且这时候可以在 JS 中操作 DOM;

     2. 设置 defer 属性

     通过给 script 标签设置 defer 属性,将脚本文件设置为延迟加载,当浏览器遇到带有 defer 属性的 script 标签时,会再开启一个线程去下载 JS 文件,同时继续解析 HTML,等
HTML 全部解析完、DOM 加载完成之后,再去执行加载好的
JS 文件。只适用于引用外部 JS 文件,并且可以确保所有加了
defer 属性的脚本会按顺序执行

     3. 设置 async 属性

     async 属性和 defer 属性类似,也是会开启一个线程去下载js文件,但和 defer 不同的是,async
会在 JS 加载完成后立刻执行,而不是会等到 DOM 加载完成之后再执行,所以还是有可能会造成阻塞。同样的也是只适用于外部 JS 文件,如果有多个设置了 async 的 JS 文件,不能像 defer 那样保证按照顺序执行

     4. 动态创建脚本    

let ma = document.createElement('script');
ma.type = 'text/javascript';
ma.src = 'http://xxxxxx/values/xtjtj?bmid=2&uuid=' + uuid;
let s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ma, s);

  ?

webpack 配置层面的优化

webpack构建结果输出分析

Webpack 输出的代码可读性非常差而且文件非常大。为了更简单、直观地分析输出结果,社区中出现了许多可视化分析工具。这些工具以图形的方式将结果更直观地展示出来,让我们快速了解问题所在。接下来讲解我们在 Vue 项目中用到的分析工具:webpack-bundle-analyzer 。

使用方法

我们在项目中 webpack.prod.conf.js 进行配置:    

if (config.build.bundleAnalyzerReport) {
    var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
    webpackConfig.plugins.push(new BundleAnalyzerPlugin());
}

                       执行 $ npm run build \--report 后生成分析报告如下:

     点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

     针对上图分析结果,外部插件体积较大,考虑到“更小的体积对于用户体验来说,就意味着更快的加载速度以及更好的用户体验。”,可以使用第三方插件的按需引入

     我们在项目中经常会需要引入第三方插件,如果我们直接引入整个插件,会导致项目的体积太大,我们可以借助 babel-plugin-component ,然后可以只引入需要的组件,以达到减小项目体积的目的。以下为项目中引入 element-ui 组件库为例:

     (1)首先,安装 babel-plugin-component :

     npm install babel-plugin-component -D

     (2)然后,将 .babelrc 修改为:    

{
    "presets": [["es2015", {"modules": false}]],
    "plugins": [
        [
            "component",
            {
                "libraryName": "element-ui",
                "styleLibraryName": "theme-chalk"
            }
        ]
    ]
}

                       (3)在 main.js 中引入部分组件:    

import Vue from 'vue';
import {Button, Select} from 'element-ui';
Vue.use(Button)Vue.use(Select)

  ?

     除了组件的按需加载还可以使用Webpack对静态资源进行压缩,这里不做详细说明。

Vue 代码层面的优化

v-if 和 v-show 区分使用场景

v-if 是真正的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建;也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。

     v-show 就简单得多, 不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 的 display 属性进行切换。

     所以,v-if 适用于在运行时很少改变条件,不需要频繁切换条件的场景;v-show 则适用于需要非常频繁切换条件的场景。

computed 和 watch 区分使用场景

computed: 是计算属性,依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed
的值时才会重新计算 computed 的值;

     watch: 更多的是「观察」的作用,类似于某些数据的监听回调
,每当监听的数据变化时都会执行回调进行后续操作;

     运用场景:

     当我们需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时,都要重新计算;

     当我们需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许我们执行异步操作 ( 访问一个API ),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。

v-for 遍历必须为 item 添加 key,且避免同时使用 v-if

(1)v-for 遍历必须为 item 添加 key

     在列表数据进行遍历渲染时,需要为每一项 item 设置唯一 key 值,方便 Vue.js 内部机制精准找到该条列表数据。当 state 更新时,新的状态值和旧的状态值对比,较快地定位到 diff。

     (2)v-for 遍历避免同`时使用 v-if

     v-for 比 v-if 优先级高,如果每一次都需要遍历整个数组,将会影响速度,尤其是需要渲染很小一部分的时候,必要情况下应该替换成 computed 属性。

     推荐使用:

     点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小    

computed: {
  activeUsers: function () {
    return this.users.filter(function (user) {
         return user.isActive
    })
  }
}

  不推荐:

     点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

事件的销毁

Vue 组件销毁时,会自动清理它与其它实例的连接,解绑它的全部指令及事件监听器,但是仅限于组件本身的事件。如果在 js 内使用 addEventListene 等方式是不会自动销毁的,我们需要在组件销毁时手动移除这些事件的监听,以免造成内存泄露,如:    

created() {
    addEventListener('click', this.click, false)
},
beforeDestroy() {
    removeEventListener('click', this.click, false)
}

图片资源懒加载

门户项目的首页一般会有很多的图片组成,为了加速首页加载速度,很多时候我们需要将页面内未出现在可视区域内的图片先不做加载,
等到滚动到可视区域后再去加载。这样对于页面加载性能上会有很大的提升,提高了用户体验。项目中使用 Vue 的 vue-lazyload 插件:

     (1)安装插件

     npm install vue-lazyload --save-dev

     (2)在入口文件 man.js 中引入并使用

     import VueLazyload from 'vue-lazyload'

     然后再 vue 中直接使用

     Vue.use(VueLazyload)

     或者添加自定义选项    

Vue.use(
    VueLazyload,
    {
        preLoad: 1.3,
        error: 'dist/error.png',
        loading: 'dist/loading.gif',
        attempt: 1
    }
)

                       (3)在 vue 文件中将 img 标签的 src 属性直接改为
v-lazy ,从而将图片显示方式更改为懒加载显示:

     <img v-lazy="/static/img/1.png">

路由懒加载

Vue 是单页面应用,首页会有很多的路由引入 ,这样使用 webpack 打包后的文件很大,当进入首页时,加载的资源过多,页面会出现白屏的情况,不利于用户体验。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应的组件,这样就更加高效了。这样会大大提高首屏显示的速度,但是可能其他的页面的速度就会降下来。

     路由懒加载例子:    

const router = new VueRouter({routes: [{
  path: '/home',
  component: () => import('@/views/home/index.vue'),
  name: 'home',
},
{
  path: '/home',
  component: () => import('@/views/home/index.vue'),
  name: 'home',

},
]})

                                                                        ----------------------------
原文链接:https://blog.51cto.com/u_7932852/3699346

程序猿的技术大观园:www.javathinker.net



[这个贴子最后由 flybird 在 2021-09-11 10:23:03 重新编辑]
  Java面向对象编程-->接口
  JavaWeb开发-->Web运作原理(Ⅰ)
  JSP与Hibernate开发-->使用JPA和注解
  Java网络编程-->通过JDBC API访问数据库
  精通Spring-->CSS过渡和动画
  Vue3开发-->通过Vuex进行状态管理
  键盘按键与 键码对照表
  vue3-Composition-API的用法
  JavaScript ES2015模块化操作
  彻底明白VUE中的done参数和函数作用
  vue中axios异步调用接口的坑
  vue中监听object数据变化的基本原理
  Vue经典面试题: Vue.use和Vue.prototype.$xx有血缘关系吗? -
  Vue项目的性能优化之路
  用Vue-Awesome-Swiper实现旋转叠加轮播效果,平移轮播效果
  HTML表单元素的用法
  JavaScript的HTML DOM Input Search 对象
  CSS 伪类
  CSS Border(边框)
  JavaScript 的HTML DOM 事件
  用JavaScript制作弹出页面
  更多...
 IPIP: 已设置保密
树形列表:   
1页 0条记录 当前第1
发表一个新主题 开启一个新投票 回复文章


中文版权所有: JavaThinker技术网站 Copyright 2016-2026 沪ICP备16029593号-2
荟萃Java程序员智慧的结晶,分享交流Java前沿技术。  联系我们
如有技术文章涉及侵权,请与本站管理员联系。