碎片化的时间,系统的整理,性能优化的知识点

  前言

  利用碎片化的时间,系统的整理,性能优化的知识点。

  前端性能优化,需要深入了解前端技术的原理。从而,做出高性能的工程,提高自身含金量。

  使用流行的性能优化技术,快速提高Web性能。了解技术背后的优秀设计思想,掌握前沿解决方案。

  前端技术栈,非常丰富。性能优化,需要一定的技术储备:

  1.掌握HTML,JavaScript,CSS,HTTP基础知识

  2.具备实际Web开发经验

  3.最好使用过Webpack,React,Chrome DevTools 等

  行业内,有很多性能优化的案例。

  性能优化的意义

  网站性能, 影响到用户参与度和用户留存,从而影响到转换率和业务收益。

  第一章 性能优化指标与测量工具

  重要性

  性能,是Web网站和应用的支柱。

  流量=》搜索=》转换率=》用户体验

  Amazon (亚马逊网上购物商城)发现:

  每100ms延迟,导致 1% 的销量损失。

  css 加载层_css根据分辨率加载不同css_nsurl加载css文件

  寻找性能瓶颈

  1.了解性能指标,多块才算快

  2.利用测量工具和API

  3.优化问题,重新测量,迭代

  优化,是一个不断迭代的过程。

  移动端挑战多

  1.设备硬件,网速,屏幕尺寸,交互方式

  2.用户更缺少耐心,超过3秒加载导致53%的跳出率

  bounce rate

  跳出率是指在只访问了入口页面(例如网站首页)就离开的访问量与所产生总访问量的百分比。

  跳出率计算公式:跳出率=访问一个页面后离开网站的次数/总访问次数

  3.持续增长的移动用户和移动电商业务

  譬如,电商网站的搜索速度

  性能指标和优化目标

  打开浏览器控制台,切换至 NetWork 选项卡

  可以看到各种资源的加载时间,通过 Waterfall 可以看到每个阶段的用时。

  譬如,TTFB(Time To First Byte)

  请求发送出去,直到返回响应结果,经历了多少时间。

  TTFB (Time To First Byte)

  是发出页面请求到接收到应答数据第一个字节的时间总和。

  它包含了DNS解析时间、 TCP连接时间、发送HTTP请求时间和获得响应消息第一个字节的时间

  切换至 Lighthouse 选项卡,显示网站性能分数。

  其中有几个指标:

  First Contentful Paint

  从白屏到出现内容

  Speed Index

  速度指数,如果比4秒小,网站就是快的。否则,就是需要优化的。

  页面加载时间

  首次渲染

  切换至 Performance 选项卡

  css 加载层_css根据分辨率加载不同css_nsurl加载css文件

  ctr + shift + p 调出指令窗口,

  输入 frame

  选择 Show frames per second (FPS) meter

  直接通过FPS视窗,查看页面的帧数

  异步请求在1秒之内,返回数据。超过1秒,前端增加加载动画。

  总结:性能优化-加载,测量指标

  1.Speed Index 速度指数

  2.TTFB (Time To First Byte)

  发出页面请求之后,接收到应答数据的第一个字节,这段时间的总和。

  3.页面加载时间,页面所有资源加载完成,所用的时间。

  4.首次渲染,第一次出现内容的时间。

  性能优化-交互

  1.交互动作的反馈时间,交互的反馈要及时。

  2.帧率FPS 帧率要足够高60FPS

  3.异步请求的完成时间,尽量在一秒之内完成。完成不了,加载动画。

  RAIL测量模型

  RAIL,以用户为核心的性能模型

  谷歌从用户体验触发,制定了性能优化的标准 RAIL

  css 加载层_css根据分辨率加载不同css_nsurl加载css文件

  RAIL是四个英语单词的首字母缩写

  1.Response 响应

  网站给用户操作的响应的体验

  2.Animation 动画

  网站动画是否流畅。如果卡顿,需要优化

  3.Idle 空闲

  合理地应用浏览器空闲时间

  4.Load 加载

  页面加载时间是最常见的性能话题

  RAIL的目标

  让良好的用户体验,成为性能优化的目标

  RAIL的评估标准

  1.Response 响应,用户操作后 100 毫秒内要得到响应

  2.Animation 动画,每一帧的渲染在 16 毫秒内完成

  3.Idle 空闲,尽可能增加空闲时间

  4.Load 加载,在 5 秒内完成内容加载并可以交换

  在优化的路上,发现问题,解决问题。

  性能测量工具

  1.Chome DevTools 开发调试,性能评测

  2.Lighthouse 网站整体质量评估

  3.WebPageTest 多测试地点,全面性能报告

  使用 WebPageTest 评估Web网站性能

  WebPageTest 提供了世界各地的服务器和各种浏览器。

  解读 WebPageTest 的报告

  1.waterfall chart 请求瀑布图

  2.first view 首次访问

  3.repeat view 二次访问

  css 加载层_css根据分辨率加载不同css_nsurl加载css文件

  使用Lighthouse分析性能

  安装 lighthouse

  <pre class="code-snippet__js" data-lang="nginx">npm install -g lighthouse</pre>

  测试网站性能

  <pre class="code-snippet__js" data-lang="nginx">lighthouse https://www.bilibili.com/</pre>

  使用 Chrome DevTools 分析性能

  ctr + shift + p 调出指令窗口,

  输入 block

  选择 Show Network request blocking

  添加过滤的js文件,过滤掉的默认不加载。

  切换至 Network 选项卡

  各种资源的大小Size 有两个,实际的大小css 加载层,和网络传输的大小。

  可以通过压缩js文件,减少网络传输的大小。

  切换至 Performance 选项卡

  点击录制按钮,开始录制新内容。页面所发生的的一切,包括交互,都会被记录下来。

  方便进行性能分析。

  常用的性能测试API

  譬如,计算可交互时间

  <pre class="code-snippet__js" data-lang="javascript">window.addEventListener('load', function() {` // 可交互时间 let timing = performance.getEntriesByType('navigation')[0]; // 计算 let tti = timing.domInteractive - timing.fetchStart;});`</pre>

  譬如,判断页面隐藏,还是显示

  <pre class="code-snippet__js" data-lang="javascript"> `let vEvent = 'visibilitychange';if(document.webkitHidden !== undefined) { vEvent = 'webkitvisibilitychange';}document.addEventListener(vEvent, function() { if(document.hidden || document.webkitHidden) { console.log('页面隐藏'); } else { console.log('页面显示'); }});`</pre>

  譬如,监听当前网络状态

  <pre class="code-snippet__js" data-lang="typescript"> // 判断当前网络状态`let connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;connection.addEventListener('change', function() { let type = connection.effectiveType; console.log('当前网络状态'+type);});`</pre>

  通过性能API可以获得关键的时间节点

  <pre class="code-snippet__js" data-lang="properties">DNS 解析耗时: domainLookupEnd - domainLookupStart`TCP 连接耗时: connectEnd - connectStartSSL 安全连接耗时: connectEnd - secureConnectionStart网络请求耗时 (TTFB): responseStart - requestStart数据传输耗时: responseEnd - responseStartDOM 解析耗时: domInteractive - responseEnd资源加载耗时: loadEventStart - domContentLoadedEventEndFirst Byte时间: responseStart - domainLookupStart白屏时间: responseEnd - fetchStart首次可交互时间: domInteractive - fetchStartDOM Ready 时间: domContentLoadEventEnd - fetchStart页面完全加载时间: loadEventStart - fetchStarthttp 头部大小:transferSize - encodedBodySize重定向次数:performance.navigation.redirectCount`重定向耗时: redirectEnd - redirectStart</pre>

  第二章 渲染优化

  首先,需要了解,浏览器渲染原理

  通过了解浏览器渲染,都经历了哪些步骤,才能有针对性的进行优化。

  核心概念:关键渲染路径 critical rendering path

  浏览器渲染,到底是一个什么样的过程?

  网络资源,譬如js文件和css文件,进行解析,最终渲染到页面上。

  浏览器的渲染流程

  JavaScript =》 Style =》Layout =》 Paint =》Composite

  1.第一步,触发视觉变化,不局限于js,有可能是css样式的改变,animation等等

  2.第二步,浏览器对样式重新进行计算,计算哪些元素的css改变

  3.第三步,布局,把元素绘制到页面上,需要知道元素的大小和位置,几何信息。

  4.第四步,绘制,把元素画到页面上,包括文字,图片,颜色,阴影,等等

  5.第五步,合成,浏览器把不同的东西画在不同的层上,然后合成到一起

  当浏览器拿到服务器返回的资源之后,它都做了些什么?

  浏览器构建对象模型

  构建DOM对象 文档对象模型

  HTML => DOM

  构建CSSOM对象

  CSS => CSSOM

  浏览器构造渲染树

  DOM CSSOM=》 Render Tree

  css 加载层_nsurl加载css文件_css根据分辨率加载不同css

  布局和绘制

  关键渲染路径中最重要的两个步骤,也是开销最高的步骤。

  减少布局和绘制的发生,可以有效地提高性能。

  渲染树,只包含网页需要的节点

  布局计算每个节点精确的位置和大小 - “盒模型”

  绘制是像素化每个节点的过程

  哪些操作,会导致布局更改,从而造成所谓的回流 reflow

  1.添加删除元素

  2.操作styles

  3.display:none

  4.offsetLeft,scrollTop,clientWidth

  5.移动元素位置

  6.修改浏览器大小,字体大小

  核心,就是位置和大小的改变。

  避免 layout thrashing (布局抖动)

  连续不断的布局回流,很容易造成页面抖动,卡顿。

  1.避免回流

  采用css3动画 translate 属性

  积攒一些之后,统一计算

  2.读写分离

  读的操作,进行完,再批量的进行写的操作

  读,读取布局信息。

  写,修改样式。

  使用 FastDom 批量对DOM的读写操作

  FastDom通过接收读写操作,并在下一帧捆绑它们(先读后写),从而消除DOM的相互影响。这意味着我们能独立编写应用程序组件,而不用担心它们在应用程序中互相影响

  github地址

  示例地址

  measure 读的操作

  mutate 写的操作

  <pre class="code-snippet__js" data-lang="javascript">fastdom.measure(() => {` console.log('measure'); fastdom.mutate(() => { console.log('mutate'); });});`</pre>

  输入

  <pre class="code-snippet__js" data-lang="javascript">fastdom.measure(() => {` console.log('measure');}); fastdom.mutate(() => { console.log('mutate');}); fastdom.measure(() => { console.log('measure');}); fastdom.mutate(() => { console.log('mutate');`});</pre>

  输出

  <pre class="code-snippet__js" data-lang="nginx">measure`measuremutatemutate`</pre>

  复合线程与图层

  复合线程 compositor

  图层 layers

  复合线程

  将页面拆分图层,进行绘制再进行复合。修改一个图层的东西,不影响其他图层。

  利用 DevTools 可以了解网页的图层拆分情况。

  减少重绘

  利用 DevTools 识别 paint 的瓶颈

  使用动画的时候css 加载层,尽量使用transform

  利用 will-change 创建新的图层

  高频事件处理函数 防抖

  <pre class="code-snippet__js" data-lang="javascript">let ticking = false;` if(ticking)return;window.requestAnimationFrame(()=>{ callback() ticking = false;`})</pre>

  第三章 代码优化

  JavaScript的开销和如何缩短解析时间

  开销在哪里?

  加载,解析编译,执行。

  解决方案:

  Code splitting 代码拆分,按需加载

  Tree shaking 代码减重

  减少主线程工作量:

  避免长任务

  避免超过1kb的行间脚本

  使用 rAF 和 rIC 进行时间调度

  V8 浏览器引擎,已经做了一些优化

  抽象语法树

  源码 =》 抽象语法树 =》 字节码Bytecode =》机器码

  编译过程会进行优化

  运行时可能发生优化

  了解V8优化机制,开发中运用这种思想

  V8优化机制

  1.脚本流

  下载过程中,超过30kb时,单独开一个线程进行解析。最后,合并所有解析完的内容。

  2.字节码缓存

  重复使用的片段,缓存起来,就不再需要翻译的过程

  3.懒解析

  需要用到时,再进行解析

  函数优化

  懒解析VS饥饿解析

  加一个括号就可以直接进行饥饿解析

  利用 Optimize.js 优化初次加载时间

  js在压缩时会自动去掉这对括号,这样就导致我们无法将想做的事情通知给解析器,这个时候我们就要用到Optimize.js了,使用Optimize.js它会帮我将去掉的括号再加回来。

  github地址:

  使用optimize-js优化JS函数

  对象优化

  以相同顺序初始化对象成员,避免隐藏类的调整

  <pre class="code-snippet__js" data-lang="javascript">class RectArea t {// HCO` constructor(l, w){ this.l = l; // HC1 this.w = w;// HC2 }}const rect1 = new RectArea(3,4)const rect2 = new RectArea(5,6)`</pre>

  实例化后避免添加新属性

  <pre class="code-snippet__js" data-lang="cs">//尽可能避免这种写法` // In-object 属性const object = {color:'red'} // Normal/Fast 属性,存储 property store 里,需要通过描述数组间接查找产生object.num = 1 `</pre>

  尽量使用Array代替 array-like 对象

  <pre class="code-snippet__js" data-lang="typescript">//不推荐这种写法`Array.prototype.forEach.call(arrObj, (value, index) => { // 不如在真实数组上效率高 console.log(value)`})</pre>

  V8 官方建议,将类数组对象,转换为真实数组,然后进行遍历。这样操作,效率更高。

  <pre class="code-snippet__js" data-lang="javascript">const arr = Array.prototype.slice.call(arrObj, 0); `arr.forEach((value, index) => { console.log(value)})`</pre>

  对象优化

  1.避免读取超过数组的长度

  在 JavaScript 中除了基础数据类型,都是对象,包括数组也是对象。

  如果,数组越界,undefined 会沿着原型链进行查找。

  2.避免元素类型转换

  元素类型越具体,编译器能做的优化就越多

  <pre class="code-snippet__js" data-lang="cpp">// 这样操作,会影响编译器的效率`const array = [3,2,1]; // PACKED SMI_ELEMENTS`array.push(4.4);//PACKED DOUBLE ELEMENTS</pre>

  HTML优化

  HTML 优化空间比较小。优化点在于,清除没有用的空间,和可以省略的元素。

  1.减小 iframe 使用

  额外添加的文档,需要加载的过程,会影响父文档的加载。

  而且,使用iframe开销更高。

  <pre class="code-snippet__js" data-lang="javascript">//使用这种写法,父文档加载后,再给iframe设置src加载资源``document.getElementById( 'a' ).setAttribute( 'src','url');</pre>

  2.压缩空白符

  打包时,压缩空白符

  3.避免节点深层级嵌套

  生成抽象语法树,嵌套的越深,遍历越慢

  4.避免table布局

  使用不灵活,开销更大

  5.删除注释,减少体积

  6.CSS 和 JavaScript 尽量外链

  7.删除元素默认属性

  借助工具

  html-minifier

  html压缩工具

  github地址:

  <pre class="code-snippet__js" data-lang="nginx">npm install html-minifier</pre>

  <pre class="code-snippet__js" data-lang="xml">var minify = require('html-minifier').minify;`var result = minify('foo', { removeAttributeQuotes: true});`result; // 'foo'</pre>

  CSS对性能的影响

  1.降低CSS对渲染的阻塞

  尽早的完成下载,譬如优先完成首屏的样式加载

  2.利用GPU进行完成动画

  对 transform 和 opacity 这样的属性,进行优化,单独建立一个层。不进行布局和重绘。

  3.使用 contain 属性

  contain 属性,大大降低了布局的时间。浏览器不会重新计算,同级其他元素。

  <pre class="code-snippet__js" data-lang="css">.news li {` contain: layout;`}</pre>

  4.使用font-display属性

  font-display属性在@font-face声明时使用。

  借助它,我们可以通过一行简单的CSS来控制字体的显示方式,而不需要使用基于JavaScript的解决方案。这意味着我们的网页可以减小体积,提高性能。

  以Vue项目举例,源码优化

  1.代码模块化

  封装组件,代码复用。通过css预加载处理器,定义css变量和混入mixin。

  2.for循环设置key值

  for循环,数据遍历渲染的时候,每一项设置唯一的值。

  为了让Vue内部核心代码能更快地找到该条数据,当旧值和新值取对比的时候,可以更快的定位到diff

  3.Vue路由懒加载

  当首屏渲染的时候,能够加快渲染速度。

  4.更加理解Vue的生命周期

  不要造成内存泄漏,使用过后的全局变量在组件销毁后重新置为null

  5.可以使用keep-alive

  keep-alive是Vue提供的一个比较抽象的组件,用来对组件进行缓存,从而节省性能。

  第四章 资源优化

  压缩合并

  资源的压缩和合并

  一直以来,资源的压缩和合并,都是最为有效的优化方案。

文章由官网发布,如若转载,请注明出处:https://www.veimoz.com/1694
0 评论
361

发表评论

!