网页性能优化

news2024/9/23 7:28:58

网页性能优化

在这里插入图片描述


文章目录

  • 网页性能优化
    • @[TOC](文章目录)
  • 前言
  • 1.前端脚本优化
    • 1.1 减少重绘、回流
    • 1.2 缓存dom选择与计算
    • 1.3 使用事件委托而不是批量绑定
  • 2.渲染优化
    • 2.1 使用CSS3开启GPU硬件加速提升网站动画渲染性能
    • 2.2 touchmove、scroll、input事件添加防抖
  • 3.加载优化
    • 3.1 合并小图片使用雪碧图
    • 3.2 压缩JavaScript和Css
    • 3.3 使用懒加载/按需加载
  • 4. 请求接口优化
    • 4.1 使用CDN(内容分发网络)
    • 4.2 添加Expire/Cache-Control头(强缓存)
    • 4.3 启用Gzip压缩
    • 4.4 尽可能减少http请求数
    • 4.5 避免重定向
    • 4.5 配置实体标签(ETag)
  • 5.css优化
    • 5.1 css内外样式写在头部
    • 5.2 避免图片、iframe空的src属性
    • 5.3 js脚本放在底部
    • 5.4 使用字体、代码代替图片
  • 6 流行框架之Vue
    • 6.1 v-if v-show的灵活使用
    • 6.2 computed、watch区分使用场景
    • 6.3 长列表性能优化,使用Object.freeze不进行数据劫持
    • 6.4 灵活使用keep-alive缓存页面
    • 6.5 v-for遍历item的key必须为业务id,不能为index索引
    • 6.6 路由销毁时解除绑定的自定义事件或定时器
    • 6.7 打包优化—工程文件打包的时候不生成.map文件(webpack)
    • 6.8 webpack【code split代码分割】
  • 7.流行架构之SSR服务端渲染
  • 8.微信小程序_摘自微信小程序官方文档
    • 8.1 合理使用分包加载
    • 8.2. 避免非必要的全局自定义组件和插件
    • 8.3 避免非必要的全局自定义组件和插件. 控制代码包内的资源文件
    • 8.4 及时清理无用代码和资源
    • 8.5 [代码注入优化](https://developers.weixin.qq.com/miniprogram/dev/framework/performance/tips/start_optimizeB.html)
    • 8.6 [首屏渲染优化](https://developers.weixin.qq.com/miniprogram/dev/framework/performance/tips/start_optimizeC.html)
    • 8.7 [其他启动性能优化建议](https://developers.weixin.qq.com/miniprogram/dev/framework/performance/tips/start_optimizeD.html)
    • 8.8 运行时性能
  • 总结

前言

随着业务的不断迭代,项目日渐壮大,为了给用户提供更优的体验,性能优化是前后端开发者避不开的话题。

他山之石可以攻玉,基于雅虎军规一十四条规范及日常开发中收集的经验,本文收录了网页性能优化策略,整个过程不似白云写《月子》般憋闷,有的只是每每的醍醐灌顶、温故知新。


1.前端脚本优化

1.1 减少重绘、回流

回流(reflow)
render树中一部分或全部元素需要改变尺寸、布局、或着需要隐藏而需要重新构建,这个过程叫做回流;
比如:添加或者删除可见的DOM元素,元素位置改变,元素尺寸改变——边距、填充、边框、宽度和高度

重绘(repaint)
render树中一部分元素改变,而不影响布局的,只影响外观的,比如颜色。该过程叫做重绘,页面至少经历一次回流和重绘(第一次加载的时候)
比如:只有颜色改变的时候就只会发生重绘而不会引起回流

如何优化
就比如 display:none 这个属性,很多人忽略了它所带的回流性能开销
如果想设定元素的样式,通过改变元素的 class 类名
除此之外, 使用 JavaScript 动态插入多个节点时, 可以使用DocumentFragment. 创建后一次插入. 就能避免多次的渲染性能.

1.2 缓存dom选择与计算

DOM是页面元素对象的体现,每次寻找的时候,都会一层层的去寻找,对于相同且已经查找过的节点,每次都去重新找,如果节点层级关系多了,性能就很低了。

// 以下不推荐
$("a").click(function(){
     $(this).xxx
     $(this).xxx
})

// 推荐写法
var $aDom = $("a")
$aDom.click(function(){
     $aDom.xxx
})

1.3 使用事件委托而不是批量绑定

事件委托:也称为事件代理(Event Delegation)。是JavaScript中常用绑定事件的常用技巧。“事件代理”即是把原本需要绑定在子元素的响应事件委托给父元素,让父元素担当事件监听的职务。
为什么要使用事件委托:工作中会碰到需要大量事件处理函数的场景,如果批量添加事件处理函数,会导致监听数量太多,造成大量内存消耗。每个事件处理函数都是一个单独的引用类型,这些函数本身也会占用内存。

<body>
    <ul id="list">
        <li>列表项</li>
        <li>列表项</li>
    </ul>

    <script>
    	var ul_list = document.getElementById('list');
    	// 以下不推荐
        var lis = ul_list.getElementsByTagName('li');
        for (var i = 0; i < lis.length; i++) {
            lis[i].onclick = function () {
            	this.style.color = 'blue';
            };
        }
        
		// 以下推荐  
        ul_list.onclick = function(e){
            e.target.style.color = 'blue';
        }
    </script>
</body>

2.渲染优化

2.1 使用CSS3开启GPU硬件加速提升网站动画渲染性能

CSS animations, transforms 以及 transitions 不会自动开启GPU加速,很多浏览器提供了某些触发的CSS规则。Chrome, FireFox, Safari, IE9+和最新版本的Opera都支持硬件加速,当它们检测到页面中某个DOM元素应用了某些CSS规则时就会开启,最显著的特征的元素的3D变换。

.cube {
   -webkit-transform: translate3d(250px,250px,250px)
   rotate3d(250px,250px,250px,-120deg)
   scale3d(0.5, 0.5, 0.5);
}

虽然我们可能不想对元素应用3D变换,可我们一样可以开启3D引擎。例如我们可以用transform: translateZ(0); 来开启硬件加速 。

.cube {
   -webkit-transform: translateZ(0);
   -moz-transform: translateZ(0);
   -ms-transform: translateZ(0);
   -o-transform: translateZ(0);
   transform: translateZ(0);
}

2.2 touchmove、scroll、input事件添加防抖

工作中遇到防抖的频率相当高,处理不当就会引起浏览器卡顿;
防抖:给定的时间内继续触发事件就会清除定时器然后重新开始计时,直到你在这个时间段内不再触发事件,才会执行func函数。


const debounce = (func, wait = 1000) => {
  let timeout;
  return function () {
    let context = this;
    let args = arguments;
 
    if(timeout) {
        clearTimeout(timeout);
    }
 
    let later = () => {
        timeout = null;
        func.apply(context, args);
    };
 
    timeout = setTimeout(later, wait);
  }

3.加载优化

3.1 合并小图片使用雪碧图

在网页中,我们可以看到有很多的小图标,比如微博上的登录位置有很多这样的小图标。如果将这些图标分别存在服务器上,那么当需要显示的时候将会发出很多次请求–>响应–>下载,这样一来将会消耗大量的时间来下载这些小图标;
所以为了提高网页响应速度,将这些小图片全部放到一张图片上,此图称为雪碧图/精灵图
在这里插入图片描述
精灵图片的使用难点在于如何在这一张图片中定位到我们需要的部分,首先我们需要理解精灵题坐标,左上角为原点,往上y值为负数,越来越小;往左x为负数,越来越小
假如我们截取第2列2排的皇冠2,此时精灵图往上移动,相当于y减小了40px(假设值),此时y坐标为-40px;往左移动24px,此时x坐标为-24px,所以如果我们需要获取vip6图标,需要如下设置;

<div class="vip6"></div>
div { width: 16px; height: 16px; background-image: url("精灵图地址"); } 
.vip6 { background-position: -24px -40px; }

3.2 压缩JavaScript和Css

去除不必要的空白符,格式符,注释符。
简写方法名,参数名压缩js脚本。

3.3 使用懒加载/按需加载

**懒加载:**如图片懒加载,Vue-Lazyload插件中的preLoad属性值可以调整懒加载滑动配置

import VueLazyload from 'vue-lazyload'
Vue.use(VueLazyload, {
  preLoad: 1.3, // 懒加载元素距离页面底部的百分比
  error: ****,
  loading: ****,
  attempt: 1 // 重试次数
})

按需加载也是重用的性能手段,当需要加载该路由时再去加载对应的路由资源

按需加载引用路由的方式
const Login = () => import('../views/Login')

原来的引用路由的方式
import Login from '../views/Login

对比原来的引入方式,就能发现不同点:现在的 Login 是个函数,当路由规则匹配上,就会执行这个函数,才去加载此组件
 {
    path: '/login',
    name: 'login',
    component: Login
  },

以下为导入组件的按需加载三种方法
import Home from '@/pages/home/index.vue'
const Home = () => import('@/pages/home/index.vue') 
const Home = resolve => require(['@/pages/home/index.vue'], resolve) 

以下为js中的按需加载/异步加载
document.getElementById('aBtn').onclick = function () {
  //异步加载A
  import('./A').then((data) => {
    alert(data.A)
  })
}

4. 请求接口优化

4.1 使用CDN(内容分发网络)

CDN:内容分发网络,意思就是尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳定。
通俗来说:就是在离你最近的地方,放置一台性能好、链接顺畅的副本服务器,让你能够以最近的距离,最快的速度获取内容
在这里插入图片描述

4.2 添加Expire/Cache-Control头(强缓存)

Expires:response header里的过期时间,浏览器再次加载资源时,如果在这个过期时间内,则命中强缓存。设置以分钟为单位的绝对过期时间, 设置相对过期时间。

Cache-Control:当值设为max-age=300时,则代表在这个请求正确返回时间(浏览器也会记录下来)的5分钟内再次加载资源,就会命中强缓存。指明以秒为单位的缓存时间。

cache-control除了该字段外,还有下面几个比较常用的设置值:

  • -no-cache:不使用本地缓存。需要使用缓存协商,先与服务器确认返回的响应是否被更改,如果之前的响应中存在ETag,那么请求的时候会与服务端验证,如果资源未被更改,则可以避免重新下载。
  • -no-store:直接禁止浏览器缓存数据,每次用户请求该资源,都会向服务器发送一个请求,每次都会下载完整的资源。
  • -public:可以被所有的用户缓存,包括终端用户和CDN等中间代理服务器。
  • -private:只能被终端用户的浏览器缓存,不允许CDN等中继缓存服务器对其缓存。

Expires优先级比Cache-Control低, 同时设置Expires和Cache-Control则后者生效.

4.3 启用Gzip压缩

HTTP压缩是在Web服务器和浏览器间传输压缩文本内容的方法。HTTP压缩采用通用的压缩算法如gzip等压缩HTML、JavaScript或 CSS文件。压缩的最大好处就是降低了网络传输的数据量,从而提高客户端浏览器的访问速度。当然,同时也会增加一点点服务器的负担。Gzip是比较常见的 一种HTTP压缩算法。

4.4 尽可能减少http请求数

HTTP:从客户端到服务器端的请求消息。包括消息首行中,对资源的请求方法资源的标识符以及使用的协议。
请求过程:当你打开网页的时候,你所看到的文字,图片,多媒体,这一切内容,都是你从服务器获取的,每一个内容的获取,就是一个http请求,可以采取合并css/js文件,合并图片如3.1,合并接口请求的方式进行优化。
在这里插入图片描述

4.5 避免重定向

定义: 原始请求被重新转向了其他请求。多了一次请求。
状态码:

  • 301(Moved Permanently):被移动到了另外的位置。
  • 302 Found:被找到了,不在原始位置,临时重定向。

在这里插入图片描述
关于如何避免重定向或者将重定向的影响降低到最小化通常有以下几种方法:

  • 删除并非绝对必要的重定向
    删除并非绝对必要的重定向,再通过其它的方式进行重定向。永远不要链接你已经知道的重定向的页面,永远不要访问经过多次重定向才能访问的资源。

  • 结尾的斜线
    通常,带有结尾带有斜线的URL表示目录,而没有带斜线的URL表示文件。
    http://example.com/foo/表示目录。
    http://example.com/foo表示文件。

  • 清理重定向链接
    除了需要删除重定向之外,还需要清理重定向链。将所有站点重定向从非www版本到www版 本,然后再重定向到https版本。例如键入“test.com”的用户重定向到“www.test.com”然后再重定向到“https:// www.test.com”,这种情况经常有发生。解决的方案是确保旧的全站点重定向不会从非www到www,而是从非www到https://www。

4.5 配置实体标签(ETag)

Last-Modify/If-Modify-Since:浏览器第一次请求一个资源的时候,服务器返回的header中会加上Last-Modify,Last-modify是一个时间标识该资源的最后修改时间;当浏览器再次请求该资源时,request的请求头中会包含If-Modify-Since,该值为缓存之前返回的Last-Modify。服务器收到If-Modify-Since后,根据资源的最后修改时间判断是否命中缓存

Etag/If-None-Match:web服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定)。If-None-Match:发现资源具有Etage声明,则再次向web服务器请求时带上头If-None-Match (Etag的值)。web服务器收到请求后发现有头If-None-Match 则与被请求资源的相应校验串进行比对,决定是否命中协商缓存;

ETag和Last-Modified的作用和用法,他们的区别
1.Etag要优于Last-Modified。Last-Modified的时间单位是秒,如果某个文件在1秒内改变了多次,那么他们的Last-Modified其实并没有体现出来修改,但是Etag每次都会改变确保了精度;
2.在性能上,Etag要逊于Last-Modified,毕竟Last-Modified只需要记录时间,而Etag需要服务器通过算法来计算出一个hash值;
3.在优先级上,服务器校验优先考虑Etag。

1.Etag要优于Last-Modified。Last-Modified的时间单位是秒,如果某个文件在1秒内改变了多次,那么他们的Last-Modified其实并没有体现出来修改,但是Etag每次都会改变确保了精度;
2.在性能上,Etag要逊于Last-Modified,毕竟Last-Modified只需要记录时间,而Etag需要服务器通过算法来计算出一个hash值;
3.在优先级上,服务器校验优先考虑Etag。
在这里插入图片描述

5.css优化

5.1 css内外样式写在头部

这样会先加载css的样式,在渲染dom的时候已经知道了自己的样式了,所以一次渲染即可成功,这样可以防止闪跳、白屏或者布局混乱的现象发生。
如果css放在底部,那么需要先渲染dom,然后加载css后会重新渲染之前的dom,这就需要两次渲染,用户体验较差。

现在浏览器为了更好的用户体验,渲染引擎会尝试尽快在屏幕上显示内容,它不会等到所有的HTMl元素解析之后在构建和布局dom树,所以部分内容将被解析并显示。也就是说浏览器能够渲染不完整的dom树和cssom,尽快的减少白屏的时间。

5.2 避免图片、iframe空的src属性

当 <script>、<img>、<iframe> 标签的 src 属性为空时,浏览器在渲染的过程中仍会将 src 属性中的空内容进行加载,直至加载失败,这样就阻塞了页面中其他资源的下载进程,而且最终加载到的内容是无效的,因此要尽量避免。

5.3 js脚本放在底部

在这里插入图片描述

src是 source 的缩写,指向外部资源的位置,指向的内容会嵌入到文档中当前标签所在的位置;在请求 src 资源时会将其指向的资源下载并应用到文档内,比如 img 图片,js 脚本等。当浏览器解析到该元素时,会暂停其他资源的下载和处理,直到将该资源加载执行完毕。这也是为什么要将 js 脚本放在底部而不是头部的原因

5.4 使用字体、代码代替图片

显而易见,是为了减少图片请求且字体图标就是将图标制作成一个字体,使用时就跟字体一样,可以设置属性,例如 font-size、color 等等,非常方便。并且字体图标是矢量图,不会失真。还有一个优点是生成的文件特别小。
使用代码代替可以描述的任何低成本图片效果。

6 流行框架之Vue

在这里插入图片描述

6.1 v-if v-show的灵活使用

v-show 是通过控制display属性来进行DOM的显示与隐藏,主要用于频繁操作;
v-if 是真正意义上的条件渲染(销毁和创建元素),条件为true时创建DOM,条件为false时销毁DOM,主要用于大量数据渲染到页面(符合条件就将数据渲染),频繁使用会消耗性能。

性能区别:

  1. v-if有更高的切换开销,v-show有更高的初始渲染开销。 如果需要频繁的切换,使用v-show比较好,如果运行条件很少改变,使用v-if比较好。
  2. v-show比v-if性能更高,因为v-show只能动态的改变样式,不需要增删DOM元素。
  3. v-if切换时候会实时的销毁和重建内部的事件、钩子函数等,v-show只会初始化渲染时候执行,再切换时候不会执行生命后期的过程。

6.2 computed、watch区分使用场景

computed:根据已有的属性生成新的属性
计算属性函数是通过函数将结果作为计算属性的值,把该计算属性挂在vm上,在模板中不能直接调用函数。计算属性的结果会被缓存,初始化时调用生成初始值,只有计算所依赖的数据发生变化才会重新计算。
在这里插入图片描述
当dirty=true时依赖的数据发生变化说明需要重新计算计算属性的返回值
当dirty=false时说明计算属性的值没有变,不需要重新计算,节省内存开销
当计算属性中的内容发生变化后,计算属性的Watcher与组件的Watcher都会得到通知。
计算属性的Watcher会将自己的dirty属性设置为true,组件的Watcher也会收到通知,从而执行render函数进行重新渲染操作,重新读取计算属性的值,此时计算属性的Wather已经把自己的dirty属性设置为true,所以会重新计算计算属性的值

watch的属性:可以监视data和computed里的已有属性
vue实例将会在实例化时调用vm.$watch()遍历watch对象的每一个属性,vm.$watch实际上是对Watcher的一种封装。

6.3 长列表性能优化,使用Object.freeze不进行数据劫持

Object.freeze方法是es5中新增加的一个属性描述符,用于锁定一个对象,被锁定后的对象将不可添加或删除属性,对自身已有属性也不可进行修改,也就是不进行数据劫持,节省内存开销
另外,freeze冻结的是堆内存中的值,和栈中的引用无关。

let obj = {  name: 'zhudying',sex: "男" }
Object.freeze(obj )
// 增加属性
obj.age = 18
console.log(obj.age)    // 输出 undefined
// 删除属性
delete obj.sex
console.log(obj)        // 输出 {  name: 'zhudying',sex: "男" }
// 修改属性
obj.sex = "女"
console.log(obj)        // 输出 {  name: 'zhudying',sex: "男" }

6.4 灵活使用keep-alive缓存页面

keep-alive 是 Vue 的内置组件,当它包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 transition 相似,keep-alive 是一个抽象组件:它自身不会渲染成一个 DOM 元素,也不会出现在父组件链中。
组件切换过程中 把切换出去的组件保留在内存中,防止重复渲染DOM,减少加载时间及性能消耗,提高用户体验性

原理: 在created钩子函数调用时将需要缓存的 VNode 节点保存在 this.cache 中/在 render(页面渲染) 时,如果 VNode 的 name 符合缓存条件(可以用 include 以及 exclude 控制),则会从 this.cache 中取出之前缓存的 VNode实例进行渲染。

参数(Props)

include - 字符串或正则表达式。只有名称匹配的组件会被缓存。
exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存。
max - 数字。最多可以缓存多少组件实例
对生命周期函数变化

被包含在 keep-alive 中创建的组件,会多出两个生命周期的钩子: activated 与 deactivated

  1. activated:在 keep-alive 组件激活时调用

  2. deactivated:在 keep-alive 组件离开时调用

正常生命周期:beforeRouteEnter --> created --> mounted --> updated -->destroyed
 
使用keepAlive后生命周期:
首次进入缓存页面:beforeRouteEnter --> created --> mounted --> activated --> deactivated
再次进入缓存页面:beforeRouteEnter --> activated --> deactivated
 
注:
1、这里的activated非常有用,因为页面被缓存时,created,mounted等生命周期均失效,你若想进行一些操作,那么可以在activated内完成(下面会举个栗子:列表页回到上次浏览位置)
2、activated   keep-alive组件激活时调用,该钩子在服务器端渲染期间不被调用。 
3、deactivated   keep-alive组件停用时调用,该钩子在服务端渲染期间不被调用。

6.5 v-for遍历item的key必须为业务id,不能为index索引

key:

  1. 辅助跟踪每个节点的身份,从而重用和重新排序现有的元素;
  2. 理想的key值是每项都有且唯一的id,“data.id”,且不能为index

假如我们存在一个ul如下,然后删除第二个元素,diff简略版分析过程如下

<ul><li v-for="item in ['111','222', '333']">{{item}}</li></ul>

原数组创建一个虚拟节点,虚拟节点里面放着js对象描述的节点,里面放着简略版的重要的属性信息, 然后虚拟dom再创建真实的dom显示显示在页面上。
当你更新了要遍历的数组,这个数组并不是重新去遍历,而是新的数组也会创建一个虚拟的dom,然后这个新的虚拟的dom会跟原来的虚拟dom进行对比,查出来不同的点再去进行相应的更新,创建最终的dom。
在这里插入图片描述

**那这个相应的更新是怎么一个原理呢:**新的虚拟dom和旧的虚拟dom对比的时候,如果想要进行旧的节点复用和重新排序是需要给每一个数组元素增加一个“唯一标识这个数组内容的key值”,比如说“111”文本唯一的标识可以是id=1,“222”为id=2,“333”为id=3,这样在新数组删除“222”的时候,“111”和“333”唯一的标识还是id=1和id=3,然后Vue在进行虚拟dom对比时,就会让新旧的id=1的“111”进行对比,没有改变就复用内容,对比id=2的“222”时,发现新的虚拟dom中没有id=2的值,那Vue就标记id=2的值被删除了,然后再对比id=3的值,发现id=3的新旧虚拟dom也是一样的,然后也会复用,所以Vue就是根据每个数组内容都有唯一标识的key来进行智能的判断是哪个位置上的哪个内容有了什么变化(删除,修改等),进而通过“重用和重新排序现有元素”来实现元素更新,最终遍历生成最终真实dom。

diff算法详细过程请看本人的另一篇文章

6.6 路由销毁时解除绑定的自定义事件或定时器

Vue 组件销毁时,会自动解绑它的全部指令及事件监听器,但是仅限于组件本身的事件

而对于定时器、addEventListener 注册的监听器等,就需要在组件销毁的生命周期钩子中手动销毁或解绑,以避免内存泄露

<script>
export default {
    created() {
      this.timer = setInterval(this.refresh, 2000)
      addEventListener('touchmove', this.touchmove, false)
    },
    beforeDestroy() {
      clearInterval(this.timer)
      this.timer = null
      removeEventListener('touchmove', this.touchmove, false)
    }
}
</script>

6.7 打包优化—工程文件打包的时候不生成.map文件(webpack)

npm run build编译之后,我们查看编译生成的文件,发现有很多.map文件,这些文件占了不小的空间。.map文件的作用是帮助编译后的代码调试,但是我们上线的代码已经调试完成,所以上线时可以不生成.map文件
在这里插入图片描述

6.8 webpack【code split代码分割】

项目内可适当进行代码合并,可减少分包,从而减少请求,按照以下配置规则可进行自检,查看是否有冗余的分包规则;
vue.config.js分包配置规则示例如下:

config.optimization.splitChunks({
	chunks: 'all', // all全部chunk,异步、同步导入的文件都进行检测; initial入口chunk,对异步导入的文件不处理;async反之;
	cacheGroups: {
		libs: {  // 分包规则1
			name: 'chunk-libs',  // 分包名称
			test: /[\\/]node_modules[\\/]/, 
			priority: 10,  // 权重数字越大权重越高,使用与多个分包规则都匹配,取数字大的权重
			minChunks: 3// 最少复用几次就分包
			minSize: 3 // ** 包达到3kb才进行分包规则,比如一个函数一个文件很小,分包反而增加了请求文件个数,反而以复制代码的方式分别放入各个组件中会少很多文件请求 **
	},
	elementUI: {***}, // 其他分包规则
	commons: {***}
});

参考文献webpack split chunks官网

7.流行架构之SSR服务端渲染

SSR全拼是Server-Side Rendering,服务端渲染。
所谓服务端渲染,指的是把vue组件在服务器端渲染为组装好的HTML字符串,然后将它们直接发送到浏览器,最后需要将这些静态标记混合在客户端上完全可交互的应用程序

在这里插入图片描述
从这张图片,我们可以知道:我们需要通过Webpack打包生成两份bundle文件:
Client Bundle,给浏览器用。和纯Vue前端项目Bundle类似
Server Bundle,供服务端SSR使用,一个json文件

左侧Source部分就是我们所编写的源代码,所有代码有一个公共入口,就是app.js,紧接着就是服务端的入口(entry-server.js)和客户端的入口(entry-client.js)。当完成所有源代码的编写之后,我们通过webpack的构建,打包出两个bundle,分别是server bundle和client bundle;当用户进行页面访问的时候,先是经过服务端的入口,将vue组件组装为html字符串,并混入客户端所访问的html模板中,最终就完成了整个ssr渲染的过程。

SSR能够在服务端先进行请求渲染,由于服务端进行请求数据的时延较小,能够快速拿到数据并且返回HTML代码。在客户端可以直接渲染数据而不需要花费一些请求数据的时间,这是服务端渲染的好处。返回内容SSR会比普通的SPA在HTML代码中多出首次渲染的结果,这样在初始化的时候直接将页面进行渲染,无需花费时间去请求数据再次渲染
SSR并不是说只在服务端进行渲染,而是说SSR会比普通的客户端渲染多一次在服务端渲染。到浏览器这边,SSR还是需要进行再次初始化Vue,并且经过beforeCreate、created、beforeMount、mounted生命周期,但是在客户端VNode进行patch的时候,如果遇到服务端渲染过的节点,那么会跳过,所以在浏览器端渲染的时候可以减少一些工作,从而提高了页面体验。

传统的SPA模式
即客户端渲染的模式:Vue.js构建的应用程序,默认情况下是有一个html模板页,然后通过webpack打包生成一堆js、css等等资源文件。然后塞到index.html中

用户输入url访问页面 -> 先得到一个html模板页 -> 然后通过异步请求服务端数据 -> 得到服务端的数据 -> 渲染成局部页面 -> 用户

SSR模式:即服务端渲染模式

8.微信小程序_摘自微信小程序官方文档

以下为启动性能优化

8.1 合理使用分包加载

使用 分包加载 是优化小程序启动耗时效果最明显的手段。建议开发者按照功能划分,将小程序的页面按使用频率和场景拆分成不同分包,实现代码包的按需加载。

分包加载具有以下优势
承载更多功能:小程序单个代码包的体积上限为 2M,使用分包可以提升小程序代码包总体积上限,承载更多的功能与服务。
降低代码包下载耗时:使用分包后可以显著减少启动时需要下载的代码包大小,在不影响功能正常使用的前提下,有效降低启动耗时。
降低小程序代码注入耗时:若未开启按需注入,小程序编译时会将所有 js 文件打包成同一个文件一次性的注入,并执行所有页面和自定义组件的代码。分包后可以降低注入和实际执行的代码量,从而降低注入耗时。
降低页面渲染耗时:使用分包可以避免不必要的组件和页面初始化。
降低内存占用:分包能够实现页面、组件和逻辑较粗粒度的按需加载,从而降低内存的占用。

此外,结合分包加载的几个扩展功能,可以进一步优化启动耗时:
8.1.1 独立分包
小程序中的某些场景(如广告页、活动页、支付页等),通常功能不是很复杂且相对独立,对启动性能有很高的要求。独立分包可以独立于主包和其他分包运行。从独立分包页面进入小程序时,不需要下载主包。建议开发者将部分对启动性能要求很高的页面放到特殊的独立分包中。

8.1.2 分包预下载
在使用「分包加载」后,虽然能够显著提升小程序的启动速度,但是当用户在使用小程序过程中跳转到分包内页面时,需要等待分包下载完成后才能进入页面,造成页面切换的延迟,影响小程序的使用体验。分包预下载便是为了解决首次进入分包页面时的延迟问题而设计的。

独立分包和分包预下载可以配合使用,获得更好的效果,详情请参考 独立分包与分包预下载教程

1.3 分包异步化
「分包异步化」将小程序的分包从页面粒度细化到组件甚至文件粒度。这使得本来只能放在主包内页面的部分插件、组件和代码逻辑可以剥离到分包中,并在运行时异步加载,从而进一步降低启动所需的包大小和代码量
分包异步化能有效解决主包大小过度膨胀的问题。

8.2. 避免非必要的全局自定义组件和插件

在 app.json 中通过 usingComponents 全局引用的自定义组件和通过 plugins 全局引入的插件,会在小程序启动时随主包一起下载和注入 JS 代码,影响启动耗时。

即使扩展库和部分官方插件不占用主包大小,但是启动时仍然需要下载和注入 JS 代码,对启动耗时的影响和其他插件并没有区别。

  • 如果自定义组件只在某个分包的页面中使用,应定义在页面的配置文件中
    • 全局引入的自定义组件会被认为是所有分包、所有页面都需要的,会影响「按需注入」的效果和小程序代码注入的耗时。
  • 如果插件只在某个分包的中使用,请仅在分包中引用插件
    • 例如:很多小程序会用到「小程序直播」插件,但是直播功能通常不在主包页面中使用或较为低频,此时建议通过分包引入「小程序直播」插件。
    • 如果确实需要在主包中或被多个分包使用的插件,仍可以考虑将插件置于一个分包,并通过「分包异步化」的形式异步引入。

8.3 避免非必要的全局自定义组件和插件. 控制代码包内的资源文件

小程序代码包在下载时会使用 ZSTD 算法进行压缩,图片、音频、视频、字体等资源文件会占用较多代码包体积,并且通常难以进一步被压缩,对于下载耗时的影响比代码文件大得多。

建议开发者在代码包内的图片一般应只包含一些体积较小的图标,避免在代码包中包含或在 WXSS 中使用 base64 内联过多、过大的图片等资源文件。这类文件应尽可能部署到 CDN,并使用 URL 引入。

8.4 及时清理无用代码和资源

除了工具默认忽略或开发者明确声明忽略的文件外,小程序打包会将工程目录下所有文件都打入代码包内。意外引入的第三方库、版本迭代中被废弃的代码或依赖、产品环境不需要的测试代码、未使用的组件、插件、扩展库,这些没有被实际使用到的文件和资源也会被打入到代码包里,从而影响到代码包的大小。

建议使用微信开发者工具提供的「代码静态依赖分析」,不定期地分析代码包的文件构成和依赖关系,以此优化代码包大小和内容。对于仅用于本地开发调试,不应包含在小程序代码包的文件,可以使用工具设置的 packOptions.ignore 配置忽略规则。

在使用打包工具(如 Webpack、Rollup 等)对小程序代码进行预处理时,可以利用 tree-shaking 等特性去除冗余代码,也要注意防止打包时引入不需要的库和依赖。

8.5 代码注入优化

小程序代码注入的优化可以从优化代码量和优化执行耗时两个角度着手。

8.6 首屏渲染优化

页面首屏渲染的优化,目的是让「首页渲染完成」(Page.onReady) 尽可能提前。但很多情况下「首页渲染完成」可能还是空白页面,因此更重要的是让用户能够更早的看到页面内容(First Paint 或 First Contentful Paint)。

8.7 其他启动性能优化建议

8.8 运行时性能

小程序的运行时性能直接决定了用户在使用小程序功能时的体验。如果运行时性能出现问题,很容易出现页面滚动卡顿、响应延迟等问题,影响用户使用。如果内存占用过高,还会出现黑屏、闪退等问题。
在优化运行时性能前,建议开发者先了解下小程序的运行环境和运行机制。
开发者可以从以下方面着手进行启动性能的优化:

  • 合理使用 setData
  • 渲染性能优化
  • 页面切换优化
  • 资源加载优化
  • 内存优化

总结

前端性能优化,路漫漫其修远兮,结合具体业务场景找到适合项目的优化方案,最后附上本人总结的优化脑图。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/69086.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

怎么修改图片分辨率提高清晰度?如何调整图片dpi分辨率?

下载的图片有时候会比较模糊&#xff0c;想要改变图片清晰度的话就需要调整图片分辨率&#xff0c;很多小伙伴都不知道怎么去修改分辨率&#xff08;在线修改照片分辨率&#xff08;DPI&#xff09; 调整图片DPI 照片dpi修改工具-压缩图&#xff09;。今天小编就教大家一个非常…

关系抽取(三)实体关系联合抽取:TPlinker

参考&#xff1a; NLP系列之封闭域联合抽取&#xff1a;CasRel、TPLinker、PRGC、PURE、OneRel&#xff0c;实在是太卷了&#xff01; - 知乎 (zhihu.com)NLP 关系抽取 — 概念、入门、论文、总结 TPlinker 论文&#xff1a;PLinker: Single-stage Joint Extraction of Entit…

乐观锁思想在 JAVA 中的实现——CAS

前言 生活中我们看待一个事物总有不同的态度&#xff0c;比如半瓶水&#xff0c;悲观的人会觉得只有半瓶水了&#xff0c;而乐观的人则会认为还有半瓶水呢。很多技术思想往往源于生活&#xff0c;因此在多个线程并发访问数据的时候&#xff0c;有了悲观锁和乐观锁。 悲观锁认为…

FinClip11月产品更新:FIDE 插件开发功能优化;开发者文档英文版上线

不知不觉 22 年进入尾声&#xff0c;通过一年的不断打磨&#xff0c;FinClip 也在不断成长&#xff0c;现在&#xff0c;让我们看看过去的 11 月&#xff0c;FinClip 又有了哪些新的变化。 产品方面的相关动向&#x1f447;&#x1f447;&#x1f447; FIDE 插件开发功能优化…

【LeetCode每日一题:1775. 通过最少操作次数使数组的和相等~~~贪心+思维题】

题目描述 给你两个长度可能不等的整数数组 nums1 和 nums2 。两个数组中的所有值都在 1 到 6 之间&#xff08;包含 1 和 6&#xff09;。 每次操作中&#xff0c;你可以选择 任意 数组中的任意一个整数&#xff0c;将它变成 1 到 6 之间 任意 的值&#xff08;包含 1 和 6&a…

另一种在ARM/x86架构处理器上部署WebDAV服务器的方法

引言 最近搞了个矿渣&#xff0c;处理器是国产的RK3328&#xff0c;四核A53架构&#xff0c;64位的&#xff0c;性能太好了&#xff0c;装了个OpenWRT&#xff0c;想用来当nas用&#xff0c;但是我发现&#xff0c;竟然没有合适的文件服务器&#xff0c;局域网内用SMB确实可以…

Java并发编程—CompletableFuture的常用方法(建议收藏)

在过去的一段时间里&#xff0c;博主一直在给大家分享多线程并发编程里面的关键CompletableFfuture类的各种技术点&#xff0c;并发编程作为java开发里面关键点之一&#xff0c;也是大家向上提升重要的一点&#xff1b;对于CompletableFuture的学习一定要学到位&#xff0c;前面…

盘点 JDK 中基于 CAS 实现的原子类

前言 JDK 中提供了一系列的基于 CAS 实现的原子类&#xff0c;CAS 的全称是Compare-And-Swap&#xff0c;底层是lock cmpxchg指令&#xff0c;可以在单核和多核 CPU 下都能够保证比较交换的原子性。所以说&#xff0c;这些原子类都是线程安全的&#xff0c;而且是无锁并发&…

第4季5:图像sensor的驱动源码的编译

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 本文演示如何修改sensor的驱动源码&#xff0c;修改之后如何编译与运行。 一、sensor的注册接口分析 这部分内容见第4季4&#xff1a;图像sensor的驱动源码解析。 二、黑电平 关于黑电平的概念&a…

[附源码]计算机毕业设计抗疫医疗用品销售平台Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

【电巢】电源管理芯片:国产化替代厂家竞逐千亿黄金赛道

前言 整个2022年三季度&#xff0c;全国新能源电动车的起火已高达600多起&#xff0c;同比上升了30%多&#xff0c;如果具体到每天来看&#xff0c;平均每天都有超过7起新能源电动车火灾发生。 7月22日&#xff0c;台湾省专业赛车手林某颖驾驶着一辆白色特斯拉Model X&#xff…

es与mysql之间的数据同步

常见的数据同步方案有三种&#xff1a; 同步调用 异步通知 监听binlog 方案一&#xff1a;同步调用&#xff08;基本不会用&#xff0c;问题太多&#xff09; 基本步骤如下&#xff1a; hotel-demo对外提供接口&#xff0c;用来修改elasticsearch中的数据 酒店管理服务在完成…

活动预告 | DataFunSummit 2022-MLOps 及 AI 工程化落地论坛

11月19日 13&#xff1a;30-17:30&#xff0c;OpenMLDB 项目发起人、第四范式技术副总裁 郑曌作为出品人发起 DataFunSummit 2022 MLOps 及 AI 工程化落地论坛。OpenMLDB PMC、第四范式资深系统架构科师 卢冕&#xff0c;将在论坛中为大家带来议题为《开源机器学习数据库 OpenM…

吃透阿里P8推荐424页Java服务端研发知识图谱后,直接入职蚂蚁P6

前言 蓦然回首自己做开发已经十年了&#xff0c;这十年中我获得了很多&#xff0c;技术能力、培训、出国、大公司的经历&#xff0c;还有很多很好的朋友。但再仔细一想&#xff0c;这十年中我至少浪费了五年时间&#xff0c;这五年可以足够让自己成长为一个优秀的程序员&#…

看场景、重实操,实时数仓不是“纸上谈兵”

本文转载自阿里云Hologres产品负责人合一在ITPUB的访谈&#xff0c;谈谈他眼中的实时数仓&#xff0c; 原文链接&#xff1a; https://mp.weixin.qq.com/s/RZMWf9r4fKV9mNoGGUtaVw 这两年&#xff0c;企业IT领域掀起实时数仓热潮。然而&#xff0c;只要稍做梳理就会发现&#…

【笔试强训】Day 6

&#x1f308;欢迎来到笔试强训专栏 (꒪ꇴ꒪(꒪ꇴ꒪ )&#x1f423;,我是Scort目前状态&#xff1a;大三非科班啃C中&#x1f30d;博客主页&#xff1a;张小姐的猫~江湖背景快上车&#x1f698;&#xff0c;握好方向盘跟我有一起打天下嘞&#xff01;送给自己的一句鸡汤&#x…

Redis - Redis为什么这么快?

1. Redis为什么这么快&#xff1f; 数据结构简单&#xff0c;对数据操作也简单&#xff0c;Redis 中的数据结构是专门进行设计的&#xff1b;基于内存实现&#xff0c;读写速度快&#xff1b;Redis 是单线程的&#xff0c;避免了不必要的上下文切换和竞争条件&#xff0c;也不…

卖座网站影院界面:优化长列表的滑动流畅度方案

关键点1&#xff1a;优化长列表的滑动流畅度 问题&#xff1a;在长列表中&#xff0c;向下滑动时&#xff0c;为了提高用户的使用感受&#xff0c;这个滑动一般都会做的很流畅。但是在网速不快的情况下&#xff0c;它自然会卡顿&#xff0c;所以为了优化网速慢带来的卡顿现象&…

好用的国产远程控制软件,我只推荐这款!

近年来&#xff0c;越来越多的人需要远程办公&#xff0c;远程为用户提供服务或支持等&#xff0c;导致人们对远程控制软件的需求不断增加。 但现在市面上远程控制软件参差不齐&#xff0c;有的远程控制软件功能不齐全&#xff0c;有的操作步骤过于繁琐&#xff0c;有的使用起…

vue 组件封装——可自由拖拽移动的盒子

最终效果 完整代码 关键性要点&#xff0c;详见注释 组件封装 superBox.vue <template><divref"box_Ref"class"box"mousedown"moveStart"mousemove"moving"mouseup"moveEnd":style"{width: (nodeInfo.width…