从 B 站出发,用 Chrome devTools performance 分析页面如何渲染
页面是如何渲染的?通常会得到“解析 HTML、css 合成 Render Tree,就可以渲染了”的回答。但是具体都做了些什么,却很少有人细说,我们今天就从 Chrome 的性能工具开始,具体看看一个页面是如何进行渲染的,以及进行页面优化时需要关注哪些指标。
以“老二次元”网站 bilibili 为例,我们将通过分析 performance 面板,串联起 Chrome 页面渲染流程,以及页面的部分量化指标的含义,来看页面具体是如何渲染的。
获取performance数据
首先,打开Chrome devTools, 选择 performace面板,点击录制按钮开始录制。
之后为了防止我们分析页面时出现无关的干扰,我们通过以下步骤降低干扰项:
1、打开 Chrome 无痕模式。
2、关闭所有在 Chrome 无痕模式下启用的拓展(如果有的话)。
3、在地址栏输入 www.bilibili.com 前,先打开 devTools,选择 performance 面板,点击录制按钮。
4、在已经录制的情况下,地址栏回车,请求 B 站,大概 10s 后,停止录制。
我们从上到下,将图分成以下几块,如下图所示:
1、控制面板
2、概览面板
3、网络面板
4、Web Vitals
5、线程面板
6、内存面板
7、聚合面板
控制面板
控制面板有 4 部分内容,分别为:
-
disable javascript samples:启用后会隐藏一些 JS 调用栈的展示。在一些性能较弱的设备例如移动端上,可以开启这项功能。
-
Network:可以用来模拟各种网络状况。
-
enableadvanced paint instrumention (slow):启用后 paint 面板会显示与绘制相关事件的更详细的信息。
CPU:可以用来模拟不同的 CPU 性能。
概览面板
概览面板是各项指标的一个概览,包含了 FPS 帧数、CPU 占用、NET 情况、内存使用情况等。
简单举个例子,比如 FPS 帧数可以直观的看出 FPS 的高低,绿色代表低的部分。而 CPU 栏的黄色代表着 js,紫色代表计算样式和布局,绿色代表绘制。
网络面板
网络面板用于展示正在请求中的各部分的组成情况。
Web vitals
Web vitals 是网站的 Web 体验指标,其中包括 LCP(最大内容绘制)、FID(首次输入延迟)、cls (累计布局偏移)等。
线程面板
线程面板用于展示渲染当前页面所使用到的线程,包含有 Main 线程、GPU 线程、Raster 线程、Chrome_ChildIOThread、Compositor 线程等等。其中 Main 线程,就是我们平时说的大部分 js 的运行环境,即主线程。
内存面板
展示 js 内存、GPU 内存、节点数、监听事件数的变化。
聚合面板
当点击主线程中的火焰图时,此面板会显示显示具体包含执行时间、执行组成、调用栈等等的信息集合。
Chrome是如何渲染页面的?
第一个请求
以第一个请求为例,我们来具体看一下 Chrome 是如何进行页面渲染的?依然是以对 https://www.bilibili.com 的请求为例,来看一下 1ms 的 performance 面板,即下图中红线部分、中间 NET 栏蓝色细长条开始的部分和 Network 中水平箱线图开始的部分。
其中两边横线中间深浅色方框的部分是水平箱线图,是用来展示某部分在整体中的比例关系。比如我们看到这个长长的箱型图,通过直观感受,就能知道对前面一部分横线挺长的,蓝色部分里浅色部分很长,深色的短,右边的横线几乎看不到。那这些又分别能展示什么信息?
首先,点开箱型图最下方的聚合面板(Summary),上面赫然写着:此乃页面源。欲求小破站, 终生皆让我……耗时一秒半。
然后在 Network tab 里查看该请求的 timing 部分,可以得到如下图:
这里的各个部分分别代表:
- Queueing(排队):浏览器会在一些情况下让请求排队等待,比如这个请求的优先级不高,有更高优先级的请求存在;在使用 HTTP/1.0 或者 HTTP/1.1 时,同域请求最大并发数量为 6 个,此时已经达到了最大值;而上图中的请求是属于最高优先级的第一个请求,即浏览器正在硬盘缓存中分配空间,从图上可以看到有 14.72ms 用于在磁盘缓存中分配空间。
Stalled(停顿):它可能会因为上述排队中的任何原因而停顿。
-
DNS lookup(DNS 查询):解析这个域名的IP地址。需要注意的是,当我们多次访问同一域名时,这部分不会出现在 timing 中。
-
Initial connection(初始连接):浏览器建立连接,包括 tcp 三次握手、重试以及协商 SSL。图中的紫色部分,就代表了在初始连接过程中的 SSL 协商部分。
-
Request sent(发送请求):正在发送请求
-
Waiting (TTFB) 等待第一字节时间:浏览器在等待第一个响应的字节,TTFB 即 Time To First Byte。这个时间包括一个往返的延迟和服务准备响应的时间之和。
-
Content Download (内容下载):浏览器正在接收响应,浏览器可以通过网络或者 serviceWorker 来直接接收。这个值是读取响应体的总时间。由于网络不佳或者浏览器正在忙于执行其他工作而延迟了对响应体的读取,读取的时间可能会比预期的要长。
这里相信已经有小伙伴注意到了,当浏览器忙于其他事情时也会让读取时间变长。也就是说,当你的 js 把主线程长期占据的时候,就会影响 content download。
下图是 Network 下的对应资源的 waterfall:
现在我们回到最开始说的各色横条上,在水平箱线图中左上角的深蓝色小方块代表着这个请求有着更高的优先级。遇到有浅蓝色的,则表示较低优先级。同时左边横线对应 Network 面板中显示的 Request Sent之前的所有事情的时间。浅色的 bar对应 Network 中 Request Sent 和 Waiting(TTFB)的时间。深色的 bar对应 Network中Content Download 的时间。右边的横线表示等待主线程所花费的时间,在 Network 面板中没有体现。
此外,可能还有些同学注意到,在蓝色箱线图上面还可以看到还有几个灰色的箱线图。不是说www.bilibili.com 是页面的第一个请求吗,难道它之前还有请求?
事实上,这个灰色箱线图相当于上一个页面的结束。如果我们是通过重新录制的方式记录 performance,那就会经历页面刷新的过程。而这几个灰色的其实就是页面刷新 unload 时发起的,是 bilibili 用来记录页面卸载时的一些数据。
说回到箱线图,可以看到在 summary 中显示 Duration 1.08 s (822.88 ms Network transfer + 260.20 ms resource loading)。这个的意思是 260ms 的时间是在 resource loading ,这里resource loading所花费的时间其实就是箱线图右侧的那条横线,等待主线程的时间。
而在 main 进程中,有横线结束的地方,可以看到解码的数据 138,933 Bytes。
这里就出现了几个问题:为什么Encode Data 33479 bytes 算下来是 33479/1024 = 32.69 k,而不是前面 Network 面板里的 33.5k ? 而且 Decode body 138993/1024 = 135.7k 也不是前面的 139k?缺少的一部分数据是什么呢?
为了验证这个问题,需要清空过去所有请求记录,重新点击录制,录制完成后,导出网络请求的 HAR 文件。使用 vscdoe 打开 json 格式的 HAR 文件,寻找 GET https://www.bilibili.com/ content-Type: text/HTML 的那个请求。经过前后的文件对比,找到了这个请求的 response content:
可以看到,图上的 size 有140682 字节。text则是 base64 编码的 HTML 内容,已经被 decode 过。需要注意的是,这里的 decode 不是对 base64 的 decode,是对 gzip 的 decode。
而在这个 text 内容之后,还有一段如下内容:
其中的 _transferSize: 35593 是网络传输的体积,即传输的体积 35593 和 decode 体积 140682。同时我们在 performance 里的主进程中的 finish loading中可以看到下图数据:
这样一看,二者是相同的。说明这个 HTML 的传输体积就是 35593 Bytes。
那为什么在 Network 面板里,我们看到的是 35.6k transferred over Network 呢?
这是因为在 Network 里展示的体积,不是除以 1024 计算的,而是除以 1000,然后四舍五入后的结果。
不过 Summary 里的 pending for xxx ms,似乎是也是等待主线程的时间,但它又是如何在 performance 体现的。目前,我还没搞清楚,如果有了解的小伙伴欢迎留言讨论~
请求其它资源
言归正传,我们现在获取到了 bilibili 网站的 HTML,接下来就需要对这个 HTML 进行处理。
通过 response header 得到 content-type:html,此时会创建一个个渲染进程,也就是主线程的这个进程。但是可以看到在主线程中的蓝色 parse HTML 之前,已经有很多 set request 被发起了,而且这些 send request 都是 HTML 文档中的一些 js 和 css。
为什么会这样呢?不应该是先解析 HTML,才能知道对哪些资源进行发起请求吗?
在 HTML 中引入的 js,存在修改 Dom 的可能,所以浏览器一般在遇到 script 标签后,会先暂停 HTML 解析,优先 js 的下载和执行。但是下载是相对耗时的,如果因为下载时间久而卡住了页面解析,很容易导致用户体验变差,因此 Chrome 采用了一些优化策略。
具体来说,就是当 Chrome 渲染引擎接收到 HTML 的字节流时候,会开启一个专门用来分析字节流中所包含 js、css 文件的预解析线程。解析到相关信息之后,预解析线程会提前开始下载这些资源文件,这样在需要使用的时候就可以直接执行,避免了下载的等待时间。
但是也能观察到,在Parse HTML蓝色方块下方,还有一些 send request,这些怎么就不是提前下载的呢?
我的理解是,这些资源其实都是在预解析线程下载的,尽管在时间上会存在重叠,但和主线程不属于同一个线程,所以 performance 工具会这么显示。但这又带来了另一个问题,为什么有些 js 明明在 HTML 的后面,却在前面就 send request 了,而有些 link/script 明明写在 HTML 里的前面,却在 performance 里后 send request?
这是跟资源的优先级有关。比如普通的 script 标签引用的资源,普通 link 引用的资源,或是rel=prelaod 或 as="style"预加载的资源,可能会被优先处理。而当资源是 prefetch,或者用 这种方式的,由于优先级低,就会被延后下载。一般的其他资源,则按顺序下载。
回到 Network,可以看到在 www.bilibil.com 的箱线图之后,是一连串 js、css、Webp 资源需要加载的请求被发起了。把鼠标移动到这些箱线图上,会看到上面有优先级 lowest low high highest,这就表示了资源的重要程度。
那么这些资源的优先级是如何评定的?一般来说,访问域名获取的 HTML、 以及预加载资源时as=“style”,拥有最高优先级。普通的
这种方式的,和不加 as="xxx"的 prefetch 预加载,就相当于异步加载,拥有最低优先级。
HTML Parse
好,到现在为止,我们已经将用到的 js、css、图片等资源下载了,然后就该进入解析 HTML 的过程了。
在 Chrome 渲染引擎内部,有个 HTMLParser 的模块。HTML 解析器负责将 HTML 转化为 Dom 结构。HTML 解析器并不是等整个文档全部获取之后才开始解析,而是加载了"足够"的数据后,就开始解析了。
在 HTML Parser 的 summary 面板里可以看到,有个Range:www.bilibili.com[0…45]。点进去看一下可以发现,定位到了 HTML 的 45 行。
这也从侧面印证了解析 HTML 的过程并不是一次全部执行完的。
HTML 的解析生成 Dom 树的过程,可以参考文章(https://medium.com/nybles/introduction-to-Dom-bee3b2dd9911)。简单来说就是将字节流转换成 token,然后把 token 解析成 Dom 节点并添加到 Dom 树中。
在 HTML 解析器工作过程中,会遇到 js、css 需要处理,比如蓝色条下面有黄色的 js 执行,有 parse stylesheet 的 css(这里的两个是 vendor.css 和 index.css)解析和 cssom 的构建。
当拿到了 vendor.css 和 index.css 这两个外部样式文件之后,就开始了 Recalculate Style 的过程,也就是在进行一些可能包括递归(比如想知道父容器的大小就得先知道子元素的大小)的样式计算。注意,这时候 HTML 还是没有完全解析完的,但是一旦样式计算结束,就开始 Layout过程。
这里的Layout对应的是将 Dom tree 和 cssom 结合成 render tree的过程。render tree 是不包含例如、display: none这些无需展示的元素。
分层
在样式计算之后,还需要经历一个pre-paint的过程,然后才能paint。
以前这里叫做 update layer tree, 2022年3月份之后改成了 pre-paint。这里其实是遍历 render tree 生成 layer tree 的过程。
render tree 和 layer tree 有啥不同呢?
render tree 是 Dom 和 cssom 结合的产物,是将计算后的样式添加到了 Dom 节点上。但是目前只是知道了节点是否可见以及可见样式,还不知道节点的精确位置和大小,这时候就需要布局。渲染引擎从 render tree 的根节点开始遍历,通过一定的规则处理后,将会得到一个 layout tree,这个 layout tree 精确的描述了每个视口内元素的位置和确切尺寸,所有的相对位置都会转变成屏幕上的绝对位置,在得知了节点是否可见、样式、位置几何信息之后,渲染引擎才有机会将 render tree 上的每个节点都转换成屏幕上的像素,这个过程也就是一般说的 绘制 paint或者栅格化 Rastering。
那 layer tree 在哪儿呢?layer tree 就在栅格化的过程当中。
在说栅格化之前,有必要提一下 Chrome 是如何将渲染视口内的内容的。
过去 Chrome 是只在用户可视区域内进行栅格化,随着用户滚动不断滚动页面而调整栅格化区域,继续栅格化并将内容填充到缺失部分。这样的缺点是当用户快速滚动的时候,页面会有卡顿感。
而现在 Chrome 采用了一种合成 composting 的方式,将页面中的某些部分分成不同的层,分别栅格化它们,然后在合成器线程中合成。这样在页面滚动时,原材料已经有了(准备好的那些层),只需要将视口内的蹭合成为一个新帧即可。这样在用户滚动时,新帧的合成效率更高。
既然需要分层,那就要知道那些元素应该在哪一层里,所以渲染引擎需要按照一定规则再遍历一次 layout tree 来创建 layer tree ,这个过程也就是 pre-paint,以前叫做 update layer tree。
分层也需要按照一定的规则,不是任意一个元素都可以被拎出来当做一层,主要是两个条件:
- 拥有层叠上下文属性的元素会被创建成图层
页面是个二维的,但是层叠上下文属性会让 HTML 元素具有三维的概念。这些元素按照自身的属性优先级分布在垂直页面的 Z 轴之上,哪些元素拥有具体参考 MDN。
- 需要被裁剪的地方会被创建为图层
当你实际的内容比容器还大的时候,就会出现裁剪,引擎会裁剪一部分内容显示在容器区域。一般来说,出现滚动条就会被创建为图层。
满足以上任意一个条件就会被提升成单独一层。
那这在 Chrome devtools 哪里可以体现呢?在 devtools -> 右侧三个点 -> more tools -> layers 里可以看到页面实际上被分成了许多层。
点击左侧的具体图层,可以看到详细的绘制过程。Details 里还有被提升为一层的原因composition reason。
Paint
通过前面分层,我们得知了元素的层级关系,但是还不知道同一层内元素的层级关系。一般来说,后面的内容会覆盖前面内容,但是浏览器该如何知道谁该覆盖谁呢?
这就需要渲染引擎为每一个图层创建绘制记录 patint record 并确定谁先画谁后画,那么后画的肯定就会覆盖先画的。绘制记录可以看做一个单向链表 div -> div -> p -> span,遍历链表即可获得绘制顺序。
现在有了图层,也有了绘制记录顺序,这些信息将会被提交到合成器线程中进行绘图和合成。由于一个图层可能会非常大,超过了视口面积,那么图层就会经历一次分割过程,分割成一个个小的图块 Tile,通常是 256256 或 512512 大小,这些图块进行会传递给栅格化线程池。池中的栅格化线程执行栅格化任务 Raster Task,将图块生成位图 bitmap,并优先生成视口附近的位图。
这个过程在performamce里叫做Rasterize Paint。
栅格化过程也会使用 GPU 来加速,一般又称为快速栅格化,GPU 栅格化。这也是为什么会有些 css 里写 will-change:transfrom 或者 transform: translateZ(0),就是为了 GPU 参与绘制。本质上是利用 will-change 和 translateZ(0) 创建了新的渲染层,从而不影响其他层级的绘制内容。
当所有的 Tile 栅格化完毕,合成器线程收集 Draw Quads 的图块信息。Draw Quads 记录了图块在内存中的位置和在页面那个位置进行绘制。然后主线程收集这些 Draw quards 信息并合成合成器帧,并交给 GPU渲染,然后才是像素出现在屏幕之上。这个过程在 perfomrance 里是 Compositie layers。
可惜我没有在 performance 里找到更详细的信息来展示这个过程。
页面渲染大概就是上述的过程,主要是结合 performance 面板串联起过去的那些知识。了解了页面渲染流程,我们该如何优化页面性能呢?又需要关注那些指标呢?
页面优化关注哪些指标
这个指标不是凭空创造,也不是仅凭感觉,这应该是一些明确的、可以量化的指标。Chrome devtool lightHouse 列举了 6 个指标。
FCP
First content paint 代表浏览器渲染出第一个 Dom content 的时间。这里的 Dom content 包括图片、非空白 canvas、svgs 等。如果你的页面里有 iframe,iframe 里的任何东西都不会被当成 Dom content。
FCP 好坏标准也是随着收集到的页面数据来不断变化的,我们可以从 httparchive 地址来查看现在世界上的页面的中位数是多少。
根据目前的指标来看,FCP 时间可以简单的分为 3 档:
0 - 1.9s,1.9s - 3s,3s以上,它们分别代表还行、很一般、不太行。
当我们在某个页面中使用 LightHouse 进行评估的时候,可能会看到尽管 FCP 只有 1s,显示的也是橙色标记。
LightHouse 里的得分是根据百分比来的。也就是说当你的 FCP 时间,是所有页面中的前 10%, 那么可以得到 90 分, 前 1% 可以得到 99 分,得到 90-100 分才会是绿色。其他的几个指标也是同样的评判标准。
影响 FCP 的原因有很多,其中一个比较常见的原因是自定义字体的加载,字体文件的加载需要一定时间,在字体文件加载完成之前,不同的浏览器会采用不同的策略。
edge:在字体准备好前使用系统字体
Chrome:隐藏文本内容。如果 3s 后自定义字体还没准备好,则使用系统字体,直到字体准备好,然后替换字体。
火狐:同 Chrome
safari:隐藏文本直到字体准备好。
一个简单的办法是在@font-face 演示里增加 font-display: swap
@font-face {font-family: 'Pacifico';font-style: normal;font-weight: 400;src: url(https://fonts.gstatic.com/s/pacifico/v12/FwZY7-Qmy14u9lezJ-6H6MmBp0u-.woff2) format('woff2');font-display: swap;
}
设置 swap 就是告诉浏览器是使用该字体的文本应该立即使用系统字体进行显示,当自定义字体准备就绪后,替换系统字体。
或者使用 prefetch / preload 来提前获取字体相关资源。
Time to intercative
TTI 标记着页面多久可以进行完全交互。
这里的完全交互是指:
-
页面已经展示了 FCP
-
事件处理函数已经为大部分可见页面元素进行了注册绑定
-
页面能够在 50ms 内对用户行为进行反应
同样我们在 httparchive 来看一下这个世界上网页 TTI 的中位数是多少。
降低 TTI 的常见思路是代码分割、按需加载,删除未使用代码、压缩代码、压缩网络负载、减少 JS 对主线程的长时间占用。
Speed Index
这个指标代表了用户感知的可见区域的页面加载的快慢。
也分成 0-3.4s 、 3.4 - 5.8、超过 5.8 三挡。但是得分也同样是跟全球网页数据来对比的。
提高 speed index 的主要是通过减少 js 对主线程阻塞,让一些非必要的 js 在 Dom 渲染后再执行。
Total Block Time
总阻塞时间。这个时间是从 FCP 到 TTI 之间所有的长任务阻塞部分的时间之和。
长任务是指执行时间超过 50ms 的任务,50ms 之后的时间量就是阻塞时间。
既然是阻塞时间,降低 TBT 的办法就是想办法减少不必要的 js 的加载、解析和执行。拆分大型脚本,对某些非同步必要的 js 使用 defer/async 或者 prefetch/preload 、或者允许的情况下进行懒加载/延迟加载、将静态资源部署到 CDN 等等。
Largest Contentful Paint
最大内容绘制。记录的是视口中最大的内容元素被渲染到屏幕的时间,也大致分为 0-2.5s、2.5s-4s、超过 4s 三个大范围。
这里的类容元素是指:
-
使用了封面的 元素
-
url() 加载的带背景图的元素
-
包含文本或者其他行内文本元素子元素的块级元素
注意,如果元素溢出到可视区域之外,则不算 LCP。
LCP 主要手4个方面的影响:
- 缓慢的服务器响应速度
应对方案:CDN、预加载、serviceWorker
- js/css 的渲染阻塞
应对方案:
1、用optimize-css-assets-Webpack-plugin、uglyifyJS之类的 Webpack 插件压缩 css、js
2、对非必要的 js、css 延迟加载,如非必要 css 用预加载,在触发事件后再去 import xx from ‘xxx’。
3、合适的情况下使用内联 css。
-
缓慢的资源加载速度
-
压缩图像
-
预加载重要资源
-
压缩文本文件 Gzip、br
-
serviceWorker 进行缓存
-
客户端渲染
-
压缩 js
-
延迟加载未立即使用的 js
-
尽可能减少polyfill。“targets”:“>0.25%”
Cumulative Layout Shift
有些时候我们会遇到,初始加载时字体忽然变大/变小, 元素位置突然移动位等。
CLS 就是通过测量发生偏移的频率来表示出页面的不稳定性。
常见的导致 CLS 比较差的原因有:
-
没指定宽高的图片
-
没有设置宽高的 iframe
-
没有设置宽高的资源位(顶部 banner、广告等)
前面提到的 无样式文本闪烁(FOUT, 用默认字体替换新字体)/ 不可见文本闪烁(FOIT,获取新字体前的显示不可见文本)。和font-display: optional结合使用
- 动画使用了修改 width、height、top、right、bottom、left 等属性值的方式来实现。应优先使用 css transfrom来实现动画。
以上就是目前 Chrome lighthouse 用来判断页面体验的 6 个指标。如果我们要优化页面,也应从这 6 个方面来入手,逐一改进,在现有的可量化指标下有的放矢。
参考资料:https://www.debugbear.com/blog/devtools-performance
相关文章:
从 B 站出发,用 Chrome devTools performance 分析页面如何渲染
页面是如何渲染的?通常会得到“解析 HTML、css 合成 Render Tree,就可以渲染了”的回答。但是具体都做了些什么,却很少有人细说,我们今天就从 Chrome 的性能工具开始,具体看看一个页面是如何进行渲染的,以及…...
Java异常Throwable的分类
1. Exception:程序本身可以捕获并且可以处理的异常 编译时异常:编译期就会检查的异常,若调用的方法中throw了此类异常,则必须进行显式处理处理(用try…catch捕获或者throws向上抛出),否则无法通…...
【mybatis的#和$使用和区别】
MyBatis是一种基于Java的持久层框架,用于将数据库操作和Java对象之间的映射进行处理。在MyBatis中,#和 $ 符号是用于SQL语句中的占位符。 在SQL语句中,#和 $ 符号都表示占位符,但它们的使用方式略有不同: # 符号 #符…...
感知趋势,洞察发展:2023(第十届)趋势与预测大会成功举办
2023年2月23日,运联年会:2023(第十届)趋势与预测大会在深圳机场凯悦酒店成功闭幕。自2014年开始,“运联年会:趋势与预测”已经连续举办九届。这场大会,既是一次行业性的“年终总结”,…...
Spring-Aop核心技术
前言spring一直以来都是我们Java开发中最核心的一个技术,其中又以ioc和aop为主要技术,本篇文章主要讲一下aop的核心技术,也就是ProxyFactory技术的使用,而基本的jdk动态代理和cglib代理技术并不涉及,如有需要ÿ…...
webpack常用优化原理剖析
webpack常用优化原理剖析 按需加载代码配置原理CDN加速-externals代码配置GZIP压缩代码配置原理Tree Shaking代码配置原理按需加载 把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件. 代码配置 //定义了一个异步函数,由于函数不调用不执行,所…...
【现在努力还不晚】--MySQL数据库的数据模型
目录 1、关系型数据库(RDBMS) 特点 2、数据模型 在学习MySQL之前要了解一下数据库的数据模型,我们就知道在MySQL当中,数据是如何存储的,我们了解一下概念! 1、关系型数据库(RDBMS࿰…...
二手商品交易网站
技术:Java、JSP等摘要:随着科学技术和信息通讯的飞速发展,Internet极大地丰富和改变着我们生活的各个行业。随着Internet的普及应用,人们可以跨越时间和空间的限制,足不出户便能通过网络完成信息交流,而完成…...
第三阶段04-同步请求和异步请求,get/post,Josn,pojo,Session/Cookie,过滤器Filter
文章目录同步请求和异步请求客户端如何发出异步请求自定义模板代码Get和Post请求异步版本的注册和登录商品管理系统(异步版本)商品列表步骤:前后端分离为什么需要前后端分离?为什么以后不再使用同步请求?JSONPOJO会话对象Session如何记住登录状态后端的MVC会话管理Cookie通过…...
Spark学习:spark相似算子解析
spark算子 一、Map、Flatmap和MapPartition二、repartition和coalesce三、reduceByKey和groupByKey四、collect、take和first一、Map、Flatmap和MapPartition 算子作用map接收一个高阶函数f,对每个算子进行f操作flatmap接收一个高阶函数f,对每个元素进行f操作,形成一个大的集合…...
MySQL操作数据表-----------创建数据表(一)
在MySQL中创建数据库完成后,需要使用USE 数据库名的形式指定进行操作的数据库,然后再去执行创建数据表的SQL语句,也可以直接使用数据库名.数据表名的形式创建数据表。 1.创建空数据表 语法格式:CREATE TABLE [IF EXISTS] 表名 &…...
Java “框架 = 注解 + 反射 + 设计模式” 之 注解详解
Java ”框架 注解 反射 设计模式“ 之 注解详解 每博一文案 刹那间我真想令时光停住,好让我回顾自己,回顾失去的年华,缅怀哪个穿一身短小的连衣裙 和瘦窄的短衫的小女孩。让我追悔少年时代,我心灵的愚钝无知,它轻易…...
特斯拉4D雷达方案首次曝光!高阶智驾市场比拼安全冗余
随着L2级智能驾驶进入普及阶段,L3/L4级赛道正在成为各家车企的下一个竞争焦点。背后的最大难题,就是如何在成本可控的前提下,保证足够的安全。 高工智能汽车研究院监测数据显示,2022年度中国市场(不含进出口ÿ…...
Echarts 每个柱子一种渐变色的象形柱状图
第023个点击查看专栏目录本示例是解决每个柱状图的每一个柱子都呈现一种渐变色,每个柱子的颜色都不同。这里同时采用了象形的柱状图效果。 文章目录示例效果示例源代码(共125行)相关资料参考专栏介绍示例效果 示例源代码(共125行&…...
叠氮试剂79598-53-1,6-Azidohexanoic Acid,6-叠氮基己酸,末端羧酸可与伯胺基反应
●中文名:6-叠氮基己酸●英文名:6-Azidohexanoic Acid,6-Azidohexanoic COOH●外观以及性质:西安凯新生物科技有限公司供应的6-Azidohexanoic Acid浅黄色或者无色油状,叠氮化物可使用铜催化的Click化学与末端炔烃共轭&…...
Nginx网站服务——编译安装、基于授权和客户端访问控制
文章目录一、Nginx概述1.1、Nginx的特点1.2、Nginx编译安装1.3、Nginx运行控制1.4、Nginx和Apache的区别二、编译安装Nginx服务的操作步骤2.1、关闭防火墙,将安装nginx所需软件包传到/opt目录下2.2、安装依赖包2.3、创建运行用户、组(Nginx 服务程序默认…...
Spring Boot 版本升级2.2.11.RELEASE至2.7.4
2.2.11.RELEASE > 2.7.4项目更新spring-boot-starter-parent 主依赖,导致项目跑不起了日志也没有输出有用信息,自己查看源码调试启动入口打断点,一步步进入方法定位项目停止代码我的项目执行到SpringApplication.class 的152行代码会停止项…...
OpenShift 4 - 使用辅助安装器安装单节点 OpenShift
文章目录单节点 OpenShift 和 OpenShift 辅助安装器单节点 OpenShiftOpenShift 辅助安装器使用辅助安装器安装单节点 OpenShift本文使用的安装环境准备环境在宿主机上安装 KVM 环境创建 SSH 证书根据集群配置,用辅助安装器生成 Discovery ISO用 Discovery ISO 启动 …...
Allegro如何快速锁定整板测试点操作指导
Allegro如何快速锁定整板测试点操作指导 在做PCB设计的时候,会需要给整板添加测试点,用于飞针测试,如下图 在测试点添加好之后,文件输出之前需要把测试点全部锁定,避免因为测试点模具开好,测试点被移动的情况出现 如果逐个锁定Via,容易遗漏 Allegro支持快速锁定整板测…...
系统分析师---知识产权标准化思维导图
保护范围以及对象(3星) 著作权法:不用申请,作品完整即保护绘画摄影作品,原件持有人只是所有权与展览权,著作权归原作者 专利法:专利权需要申请商标法:商标权需要申请反不正当竞争法…...
HiEV洞察 | 特斯拉HW4.0再爆猛料,高精定位、雷达均有变动
作者 | 查理斯 编辑 | 王博特斯拉 HW4.0 消息传出后,有人爆料说在硬件层面发生了巨大变化,引发行业轰动。大家都在猜测HW4.0 具体做了哪些改动。 2月16日,Twitter用户greentheonly爆出HW4.0的主板拆解照片。2月18日又爆出毫米波雷达的拆解照片…...
潜伏的 Linux Rootkit:Syslogk
Rootkit 是非常危险的恶意软件,一旦侵入就很难被发现。开发 Rootkit 通常更加困难,很多攻击者都倾向于重用开源项目。 Adore-Ng 是一个相对较老的、开源的 Linux 内核 Rootkit,最初针对内核 2.x 版本开发,但目前已更新为针对内核…...
JVM总结
1. 内存结构 线程私有区 程序计算器 作用:是一块较小的内存空间,存储的是当前线程所执行的字节码文件的序号特点:线程私有,不会出现内存空间溢出 虚拟机栈 虚拟机栈是管理JAVA方法执行的内存模型,每个方法执行时都…...
AOF:redis宕机,如何避免数据丢失
由于redis是基于内存的数据库,一旦宕机,数据就会丢失?如何解决? 目前,Redis 的持久化主要有两大机制,即 AOF(Append Only File)日志和 RDB(Redis DataBase) 快照。 AO…...
LC-3—MIO、MMIO、Caller Save、Callee Save
LC-3—MMIO、Caller Save、Callee SaveMMIOCaller Save、Callee Save举个例子MMIO MMIO(Memory Mapped I/O)是一种在系统内存中映射I/O端口的技术,它允许设备直接访问内存中的特定地址,从而实现I/O操作。MMIO技术可以提高I/O操作…...
SQL注入报错注入之floor()报错注入原理分析
简介 对于SQL注入的报错注入通常有三个函数需要我们掌握: extractValue(xml_frag, xpath_expr)updateXML(xml_target, xpath_expr,new_xml)floor() 对于extractValue和updateXML函数来说比较好理解,就不做解释了,这里只对floor函数的报错注…...
2023CS双非保研985经验分享(南大、华科、中科大科学岛、国防科大、西交、中南、深圳大学、北邮、中科院等)
前言: 2022保研以来,因为自己的双非背景,要与985、211的排名靠前的计科大佬竞争,不自信、焦虑无时无刻的包围着我;所幸,一路以受到了许多学长、学姐耐心的帮助,也有很多保研的同学一路互相支撑。…...
Shell中的IFS
IFS是shell的内置变量,IFS是一个字符串,里面的每一个字符都会用来作为分隔符进行单词分割。 IFS变量只在当前shell起作用。 一、对$*的影响 先做参数替换把$*替换成参数列表。相当于args[] 然后下面分两种情况: (1)…...
Java学习线路图--书籍推荐
----基础---- 《Java从入门到精通》 ----进阶---- 一 《Java项目开发全程实录》《Java开发实例大全(基础篇)》《Java开发实例大全(提高篇)》 二 《Java Web从入门到精通》《Java Web项目开发全程实录》《Java Web开发实例大…...
【GO】k8s 管理系统项目23[前端部分–工作负载-Pod]
k8s 管理系统项目[前端部分–工作负载-Deployment] 1. 代码部分 1.1 准备工作 由于Pod页面和Deployment内容差不多.那么就直接把Deployment的内容复制过来.再做修改. 替换Deployment为Pod替换Deploy为Pod替换deployment为pod替换deploy为pod禁用新增的按钮,删除新增方法,表…...
phicomm怎么做网站/企业关键词排名优化网址
前几天读研时候上铺的同学和我说到了一个问题,就是他们单位的redhat服务器给MySQL服务的数据库文件所在的磁盘空间不够了,对于这个问题我也是没有想过的,在受朋友之托下考虑自己做下复现,由于同学所在单位存放的时全省的交易记录&…...
广元市城乡规划建设监察大队网站/新媒体销售好做吗
分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!实验软件环境:虚拟机Vmware Work…...
中国建筑装饰网注册用户名/优化神马网站关键词排名价格
文章目录1. 按2. 代码1. 按 判断两个文件是否相同需要用到filecmp模块: filecmp.cmp(f1, f2, shallowTrue) 比较名为f1和f2的文件,如果它们似乎相等则返回True,否则返回False 如果shallow为真,那么具有相同os.stat()签名的文件将…...
wordpress 内容 管理/推广方案框架
一:背景1. 讲故事前段时间写了几篇 C# 漫文,评论留言中有很多朋友多次提到 Span,周末抽空看了下,确实是一个非常 的新结构,让我想到了当年的WCF,它统一了.NET下各种零散的分布式技术,包括&#…...
b2b网站建设报价/浙江网站推广
毫无疑问,Linux是微软的竞争对手。但是,微软为什么还要给Linux贡献驱动源代码,助Linux一臂之力?岂非头脑发疯了?事实究竟是怎样的? 7月21日下午两点,有一位朋友从美国打电话给我,他对…...
网站 用户体验/淘宝代运营公司排名
登录页面 我们首先来实现登录页面的功能,将使用Django提供的默认登录视图函数,因此ULR模式会稍有些不同 在目录learning_log/users/中,新建一个名为users.py文件修改urls.py """为应用程序users定义URL模式"""…...