如何创建本地站点,wordpress照片exif,深圳网络推广运营企业,优化网站 主题前言前端代码离不开浏览器环境#xff0c;理解 js、css 代码如何在浏览器中工作是非常重要的。如何优化渲染过程中的回流#xff0c;重绘#xff1f;script 脚本在页面中是怎么个加载顺序#xff1f;了解这些对前端性能优化起着非常大的作用。借着这篇文章#xff0c;让自…前言前端代码离不开浏览器环境理解 js、css 代码如何在浏览器中工作是非常重要的。如何优化渲染过程中的回流重绘script 脚本在页面中是怎么个加载顺序了解这些对前端性能优化起着非常大的作用。借着这篇文章让自己对这块知识的理解更深一步。渲染渲染树(Render Tree)浏览器通过解析 HTML 和 CSS 后形成对应的 DOM 树和 CSSOM 树。从根节点开始解析 DOM 树节点并匹配对应的 CSSOM 样式规则选择可见的的节点最终结合成一颗渲染树。从上图能看到渲染树的特点渲染树中不包含 head、script、link、meta 之类不可见的节点CSS 定义的样式规则将和实际的 DOM 匹配并且被 display:none 修饰的节点最终不会出现在渲染树中渲染阶段根据上图整个渲染阶段分为三部分渲染树的形成通过 DOM 和 CSSOM 形成渲染树布局 Layout(自动重排 Reflow)基于页面的流式布局遍历渲染树节点不断计算节点最终的位置几何信息样式等属性后输出一个“盒模型”绘制 Paint(栅格化)将节点位置大小根据屏幕的窗口大小换算成真实的像素同颜色等属性一同“画到”页面上回流和重绘基本概念回流 Reflow某些元素位置、几何形状的更改需要浏览器重新计算相关元素。重绘 Repaint将回流重排好的元素绘制到页面上但也因某些 js、css 的修改导致渲染树发生变化浏览器需要再次绘制页面。两者的关系触发回流一定会触发重绘, 而触发重绘却不一定会触发回流下图很形象的展示了 Mozilla 页面的渲染过程。触发回流条件首次布局渲染页面改变浏览器窗口大小改变字体网页内容变化触发 CSS 伪类操作 DOMstyle 样式表发生变化调用 DOM 元素的 offsetXX, clientXXscrollXXgetClientRects 等属性方法获取元素当前的位置度量信息(参见)如何测试网页性能都知道频繁的渲染过程会影响网页性能但怎么知道网页开始渲染内容了呢我们可以通过 Chrome 的 F12选择 Rendering 来查看网页的性能。Paint flashing: 以绿色高亮重绘区域Layout Shift Regions: 以蓝色高亮布局发生变化的区域结合上面的方法用 一个简单的 Demo 来示意能从图中看到这些操作 触发了浏览器的重绘鼠标移至按钮上触发了默认的 hover 效果(出现绿框)改变元素 color 属性(出现绿框)修改元素 top 属性不断改变元素位置影响布局(出现绿框蓝框)提升渲染性能布局/回流 和 绘制/重绘 是页面渲染必须会经过的两个过程不断触发它们肯定会增加性能的消耗。浏览器会对这些操作做优化(把它们放到一个队列批量进行操作)但如果我们调用上面提到的 offsetXX, clientXXscrollXXgetClientRects 等属性方法就会强制刷新这个队列导致这些队列批量优化无效。下面列举一些简单优化方式不要使用 table 布局 table 布局会破坏 HTML 流式解析过程甚至内部元素改动会触发整个 table 重绘将需更改的 class 放到最里层 明确元素位置减少父类元素不必要渲染判断使用 fixed、absolute 属性修饰复杂多变的处理(动画) 将改变范围降到最低程度避免影响到父级元素合并减少 DOM 操作通过虚拟 DOM 来代替脚本的加载link 和 script 加载文件的差异注均放在 head 标签内。考个问题CSS 定义在 head 中其需加载 5 秒请问页面加载后内容会先优先展示吗 我被渲染出来了 我原先以为页面内容会优先渲染CSS 加载完成后才改变内容样式。其实这是错的。从上图看到页面加载后body 内元素就已经解析好了只是没有渲染到页面上。随后 CSS 文件加载后带有样色的内容才被渲染到页面上。延迟的 link 的加载阻断了页面渲染但并没有影响 HTML 的解析当 CSS 加载后DOM 完成解析CSSOM 和 DOM 形成渲染树最后将内容渲染到页面上。反问将 link 替换成 script 效果也一样吗与 link 不同script 的加载会阻断页面 HTML 的解析浏览器解析完 script 后会等待 js 文件加载完后页面才开始后续的解析body 内容才出现。head 和 body 中的 script 标签学前端时相信都听过这样的名言CSS 写在 head 里js 写在 body 结束标签前知道了上面 link 和 script 的区别后应该明白前半句的含义下面来解释下后半句。下面 script 均在 body 中。页面渲染 和 script 加载先看下脚本在 body 中的一般情况在 body 内部的首位分别加载两个 js 文件前者延迟 3 秒后者延迟 5 秒为了清楚他们的“工作”情况在 head 中添加了定时器示意。 我被渲染了 能看到 body 中定义的内联脚本首先工作初始化 foo 变量。随后加载 addTen.js并阻断页面渲染。3 秒后输出 js 内容(foo 赋值为 10)页面并重新开始解析展示 div 内容。最后加载 addOne.js 继续等待 2 秒后输出 js 内容(foo 赋值为 11)。多个 script 文件的加载如果前一个 js 文件加载慢于后一个会有怎么个效果我被渲染了两个 script 标签并行加载1 秒后 addOne.js 首先加载完毕等待 4s 秒后addTen.js 加载完后页面直接渲染(因为 script 已经全部完成)。简单总结下无论在 head 还是 body 中浏览器会等待 script 文件的加载(阻断页面解析渲染)多个 script 的文件加载是异步的不存在互相影响(后一个文件不需要等待前一个加载完后才下载)执行顺序同定义顺序所以建议 script 放在 body 结束标签之前确保页面内容全部解析完成并开始渲染。DOM 的 DOMContentLoaded 事件DOMContentLoaded 事件可以来确定整个 DOM 是否全部加载完成下面我们简单测试下我被渲染了最终输出addTen.jsfoo 10addOne.jsfoo 11[ready] documentDOMContentLoaded 事件的定义是异步回调方式当 DOM 加载完成后触发即使写在最前面也会等待后面的 script 加载完成后才触发。这里顺便提个 window.onload window.onload 和 DOMContentLoaded 不同前者会等待页面中所有的资源加载完毕后再调用执行(比如img 标签)后者在 DOM 加载完毕后即触发。“真正的异步脚本”——动态脚本能看到无论 script 放在那个位置浏览器都会等待他们直至 body 内的文件全部加载完。那有什么 真正的异步 脚本加载吗(不会阻断页面解析)那就是 动态脚本。如果你接触过第三方网页统计脚本那将比较了解下面给段示例代码我被渲染了最终输出addTen.jsafoo 10addOne.jsfoo 11[ready] document已加载 5 秒已加载 6 秒已加载 7 秒已加载 8 秒dynamicScript.js is runningdynamicScript.js loaded已加载 9 秒已加载 10 秒定义了需要加载 8 秒的 dynamicScript.js 文件所有的 script 加载方式依旧异步但 dynamicScript.js 在 DOMContentLoaded 触发后最后才执行浏览器并没有等待它的加载完成后才渲染页面。我们也可以将它放在 head 中。这种通过脚本来动态修改 DOM 结构的加载方式是 无阻塞式 的不受其他脚本加载的影响。defer 和 async我们可以在 script 定义 defer 、 async 使整个脚本加载方式更加友好。比如被修饰的脚本在 head 中将不会阻断 body 内容的展示。注意 defer 修饰的脚本将延迟到 body 中所有定义的脚本之后DOM(页面内容)加载完之前触发 async 不会像 defer 一样等待 body 中的脚本而是当前脚本一加载完毕就触发。 我被渲染了 加载顺序已加载 1 秒已加载 2 秒scriptAsync.js已加载 3 秒已加载 4 秒addTen.jsfoo 10addOne.jsfoo 11scriptDefer.js[ready] document已加载 5 秒已加载 6 秒已加载 7 秒已加载 8 秒dynamicScript.js is runningdynamicScript.js loaded已加载 9 秒已加载 10 秒本文使用 mdnice 排版