Web 前端性能优化之六:构建优化

5、渲染优化

如果把浏览器呈现页面的整个过程一分为二,前面章节所讨论的诸如图像资源优化、加载优化,以及构建中如何压缩资源大小等,都可视为浏览器为呈现页面请求所需资源的部分;本章将主要关注浏览器获取到资源后,进行渲染部分的相关优化内容。

其实优化渲染的实质,就是尽量压缩每个阶段的执行时间或跳过某些阶段的执行。

目前大部分设备的屏幕分辨率都在60fps左右,也就是每秒屏幕会刷新60次,所以要满足用户的体验期望,就需要浏览器在渲染页面动画或响应用户操作时,每一帧的生成速率尽量接近屏幕的刷新率。若按照60fps来算,则留给每一帧画面的时间不到17ms,再除去浏览器对资源的一些整理工作,一帧画面的渲染应尽量在10ms内完成,如果达不到要求而导致帧率下降,则屏幕上的内容会发生抖动或卡顿。

1、渲染过程

渲染过程大体可以划分为五个部分:JavaScript处理、计算样式、页面布局、绘制与合成。

JavaScript处理:前端项目中经常会需要响应用户操作,通过JavaScript对数据集进行计算、操作DOM元素,并展示动画等视觉效果。当然对于动画的实现,除了JavaScript,也可以考虑使用如CSS Animations、Transitions等技术。

计算样式:在解析CSS文件后,浏览器需要根据各种选择器去匹配所要应用CSS规则的元素节点,然后计算出每个元素的最终样式。

页面布局:指的是浏览器在计算完成样式后,会对每个元素尺寸大小和屏幕位置进行计算。由于每个元素都可能会受到其他元素的影响,并且位于DOM树形结构中的子节点元素,总会受到父级元素修改的影响,所以页面布局的计算会经常发生。

绘制:在页面布局确定后,接下来便可以绘制元素的可视内容,包括颜色、边框、阴影及文本和图像。

合成:通常由于页面中的不同部分可能被绘制在多个图层上,所以在绘制完成后需要将多个图层按照正确的顺序在屏幕上合成,以便最终正确地渲染出来。

在这里插入图片描述

渲染过程
2、JavaScript 执行优化
1、JavaScript 实现的动画的优化:使用 requestAnimationFrame

前端实现动画效果的方法有很多,比如在CSS中可以通过transition和animation来实现,在HTML中可以通过canvas来实现。

而通过 JavaScript 实现的动画,最容易想到的方式是利用定时器setTimeout或setInterval来实现。

但不要用 setTimeout或setInterval,而是用 requestAnimationFrame。

requestAnimationFrame方法的执行时机会与系统的刷新频率同步。这样就能保证回调函数在屏幕的每次刷新间隔中只被执行一次,从而避免因随机丢帧而造成的卡顿现象。

在这里插入图片描述

2、恰当使用 Web Worker

可将一些纯计算的工作迁移到Web Worker上处理,它为JavaScript的执行提供了多线程环境,主线程通过创建出Worker子线程,可以分担一部分自己的任务执行压力。在Worker子线程上执行的任务不会干扰主线程,待其上的任务执行完成后,会把结果返回给主线程,这样的好处是让主线程可以更专注地处理UI交互,保证页面的使用体验流程。需要注意的是,Worker子线程一旦创建成功就会始终执行,不会被主线程上的事件所打断,这就意味着Worker会比较耗费资源,所以不应当过度使用,一旦任务执行完毕就应及时关闭

●DOM限制:Worker无法读取主线程所处理网页的DOM对象,也就无法使用document、window和parent等对象,只能访问navigator和location对象。

●文件读取限制:Worker子线程无法访问本地文件系统,这就要求所加载的脚本来自网络。

●通信限制:主线程和Worker子线程不在同一个上下文内,所以它们无法直接进行通信,只能通过消息来完成。

●脚本执行限制:虽然Worker可以通过XMLHTTPRequest对象发起ajax请求,但不能使用alert()方法和confirm()方法在页面弹出提示。

●同源限制:Worker子线程执行的代码文件需要与主线程的代码文件同源。

Web Worker的使用方法非常简单,在主线程中通过new Worker()方法来创建一个Worker子线程,构造函数的入参是子线程执行的脚本路径,由于代码文件必须来自网络,所以如果代码文件没能下载成功,Worker就会失败:

在这里插入图片描述

在子线程处理完相关任务后,需要及时关闭Worker子线程以节省系统资源,关闭的方式有两种:在主线程中通过调用worker.terminate()方法来关闭;在子线程中通过调用自身全局对象中的self.close()方法来关闭。

考虑到上述关于Web Worker使用中的限制,并非所有任务都适合采用这种方式来提升性能。如果所要处理的任务必须要放在主线程上完成,则应当考虑将一个大型任务拆分为多个微任务,每个微任务处理的耗时最好在几毫秒之内,能在每帧的requestAnimationFrame更新方法中处理完成,代码示例如下:

在这里插入图片描述

3、事件节流和事件防抖

所谓事件节流,简单来说就是在某段时间内,无论触发多少次回调,在计时结束后都只响应第一次的触发。代码示例如下:

在这里插入图片描述

事件防抖的实现方式与事件节流类似,只是所响应的触发事件是最后一次事件。具体来说,首先设定一个事件防抖的时间间隔,当事件触发开始后启动计时器,若在定时器结束计时之前又有相同的事件被触发,则更新计时器但不响应回调函数的执行,只有当计时器完整计时结束后,才去响应执行最后一次事件触发的回调函数。

在这里插入图片描述

如果用户操作过于频繁,每次在防抖定时器计时结束之前就进行了下一次操作,那么同一事件所要触发的回调函数将会被无限延迟。频繁延迟会让用户操作迟迟得不到响应,同样也会造成页面卡顿的使用体验,这样的优化就属于弄巧成拙。

如果用户操作过于频繁,每次在防抖定时器计时结束之前就进行了下一次操作,那么同一事件所要触发的回调函数将会被无限延迟。频繁延迟会让用户操作迟迟得不到响应,同样也会造成页面卡顿的使用体验,这样的优化就属于弄巧成拙。

在这里插入图片描述

4、恰当的 JavaScript 优化

通过优化执行JavaScript能够带来的性能优化,除上述几点之外,通常是有限的。很少能优化出一个函数的执行时间比之前的版本快几百倍的情况,除非是原有代码中存在明显的BUG。

若花费大量精力进行这类微优化,可能只会带来零点几毫秒的性能提升,当然如果基于游戏或大量计算的前端应用,则另当别论。所以对于渲染层面的JavaScript优化,我们首先应当定位出导致性能问题的瓶颈点,然后有针对性地去优化具体的执行函数,而避免投入产出比过低的微优化。

Chrome浏览器开发者工具中的Performance页签,使用它可让我们逐帧评估JavaScript代码的运行开销。

在工具的顶部有控制JavaScript采样的分析器复选框Disable JavaScript samples,由于这种分析方式会产生许多开销,建议仅在发现有较长时间运行的JavaScript脚本时,以及需要深入了解其运行特性时才去使用。除此之外,在可开发者工具的Setting 〉 More tools中单独调出JavaScript分析器针对每个方法的运行时间及嵌套调用关系进行分析,并可将分析结果导出为.cpuprofile文件保存分享。

在这里插入图片描述

JavaScript Profiler工具界面

该功能将帮助我们获得更多有关JavaScript调用执行的相关信息,据此可进一步评估出JavaScript对应用性能的具体影响,并找出哪些函数的运行时间过长。然后使用优化手段进行精准优化。比如尽量移除或拆分长时间运行的JavaScript脚本,如果无法拆分或移除,则尝试将其迁移到Web Worker中进行处理,让浏览器的主线程继续执行其他任务。

3、计算样式优化
1、减少要计算样式的元素数量:使用类选择器替代标签选择器

在这里插入图片描述

CSS选择器的匹配规则实际上是从右向左的,这样再回看上面的规则匹配,其实开销相当高,因为CSS引擎需要首先遍历页面上的所有li标签元素,然后确认每个li标签有包含类名为product-list的父元素才是目标元素,所以为了提高页面的渲染性能,计算样式阶段应当尽量减少参与样式计算的元素数量:

  • 使用类选择器替代标签选择器

    对于上面li标签的错误示范,如果想对类名为product-list下的li标签添加样式规则,可直接为相应的li标签定义名为product-list_li的类选择器规则

  • 避免使用通配符做选择器

    在这里插入图片描述

    使用通配符就意味着在计算样式时,浏览器需要去遍历页面中的每一个元素,这样的性能开销很大,应当避免使用。

2、降低选择器的复杂性

在这里插入图片描述

比如使用名为final-container-content的类选择替代上述的复杂样式计算,直接添加到目标元素上。而且复杂的匹配规则,可能也会存在考虑不周从而导致画蛇添足的情况,例如,通过id选择器已经可以唯一确定目标元素了,就无须再附加其他多余的选择器:

在这里插入图片描述

3、使用 BEM 规范:最好只有一个选择器

BEM是一种CSS的书写规范,它的名称是由三个单词的首字母组成的,分别是块(Block)、元素(Element)和修饰符(Modifier)。理论上它希望每行CSS代码只有一个选择器,这就是为了降低选择器的复杂性,对选择器的命名要求通过以下三个符号的组合来实现。

●中画线(-):仅作为连字符使用,表示某个块或子元素的多个单词之间的连接符。

●单下画线(_):作为描述一个块或其子元素的一种状态。

●双下画线(__):作为连接块与块的子元素。

通常来说,凡是独立的页面元素,无论简单或是复杂都可以被视作一个块,在HTML文档中会用一个唯一的类名来表示这个块。具体的命名规则包括三个:只能使用类选择器,而不使用ID选择器;每个块应定义一个前缀用来表示命名空间;每条样式规则必须属于一个块。比如一个自定义列表就可视作为一个块,其类名匹配规则可写为:

在这里插入图片描述

元素即指块中的子元素,且子元素也被视作块的直接子元素,其类名需要使用块的名称作为前缀。以上面自定义列表中的子元素类名写法为例,与常规写法对比如下:

在这里插入图片描述

修饰符可以看作是块或元素的某个特定状态,以按钮为例,它可能包含大、中、小三种默认尺寸及自定义尺寸,对此可使用small、normal、big或size-N来修饰具体按钮的选择器类名,示例如下:

在这里插入图片描述

BEM样式编码规范建议所有元素都被单一的类选择器修饰。

4、页面布局与重绘的优化

页面布局也叫作重排和回流,指的是浏览器对页面元素的几何属性进行计算并将最终结果绘制出来的过程。凡是元素的宽高尺寸、在页面中的位置及隐藏或显示等信息发生改变时,都会触发页面的重新布局。

1、触发页面布局与重绘的操作
  • 第一类:

    对DOM元素几何属性的修改,这些属性包括width、height、padding、margin、left、top等,某元素的这些属性发生变化时,便会波及与它相关的所有节点元素进行几何属性的重新计算,这会带来巨大的计算量;

  • 第二类:

    更改DOM树的结构,浏览器进行页面布局时的计算顺序,可类比树的前序遍历,即从上向下、从左向右。

    这里对DOM树节点的增、删、移动等操作,只会影响当前节点后的所有节点元素,而不会再次影响前面已经遍历过的元素。

  • 第三类:

    获取某些特定的属性值操作,比如页面可见区域宽高offsetWidth、offsetHeight,页面视窗中元素与视窗边界的距离offsetTop、offsetLeft,类似的属性值还有scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientWidth、clientHeight及调用window.getComputedStyle方法。

    这些属性和方法有一个共性,就是需要通过即时计算得到,所以浏览器就需要重新进行页面布局计算。

2、避免对样式的频繁改动

如果一定要修改样式,则可通过以下几种方式来降低触发重排或回流的频次:

1、使用类名对样式逐条修改

在这里插入图片描述

2、缓存对敏感属性值的计算

在这里插入图片描述

3、使用 requestAnimationFrame 方法控制渲染帧

在requestAnimationFrame方法的回调函数中,应始终优先样式的读取(requestAnimationFrame方法可以控制回调在两个渲染帧之间仅触发一次,如果在其回调函数中一开始就取值到即时敏感属性,其实获取的是上一帧旧布局的值,并不会触发页面布局的重新计算。),然后再执行相应的写操作:

在这里插入图片描述

3、通过工具对绘制进行评估
1、监控渲染信息

打开Chrome的开发者工具,可以在“设置”→“更多工具”中,发现许多很实用的性能辅助小工具,比如监控渲染的Rendering工具:

在这里插入图片描述

  • Paint flashing,当我们开启该功能后,操作页面发生重新渲染,Chrome会让重绘区域进行一次绿色闪动。

    这样就可以通过观察闪动区域来判断是否存在多余的绘制开销,比如若仅单击Select组件弹出下拉列表框,却发现整个屏幕区域都发生了闪动,或与此操作组件的无关区域发生了闪动,这都意味着有多余的绘制开销存在,需要进一步研究和优化。

    在这里插入图片描述

    店铺管理系统在切换一级菜单项时,牵涉二级菜单的图层闪动情况
  • Layer borders功能开启后,会在页面上显示出绘制的图层边界。

  • FPS meter功能开启后,会在当前页面的左上角显示实时的帧率情况,GPU功能是否开启及GPU内存占用情况

    在这里插入图片描述

    Rendering工具对帧率的监控
2、查看图层详情

当我们通过Rendering工具发现存在有多余的图层渲染时,由于闪动是难于捕捉的,所以还需要工具辅助显示出各个图层的详细信息,这便需要用到Layers图层工具。

在这里插入图片描述

Layers图层工具

上图所示工具界面大体分为三部分,

①号矩形框区域为当前页面的图层列表;

②号矩形框区域为页面带有图层边框的视图;

③号矩形框区域为选中图层的详细信息,包括页面尺寸、内存占用、绘制次数等。

通过这些信息能够帮助我们快速定位到所要查看的图层信息。当我们使用Rendering工具监控页面交互过程中有不恰当的图层存在时,便可使用Layers工具进行问题复现:首先打开目标页面,然后从左侧图层列表中依次查找出问题图层,接着分析引起该图层发生重绘的原因。

4、降低绘制复杂度

绘制是在页面布局确定后,将元素的可视内容绘制到屏幕上的过程。虽然不同的CSS绘制样式看不出性能上明显的不同,但并非所有属性都有同样的性能开销。例如,绘制带有阴影效果的元素内容,就会比仅绘制单色边框所耗费的时间要长,因为涉及模糊就意味着更高的复杂度。CSS属性如下:

在这里插入图片描述

比如位图的阴影效果,可以考虑使用Photoshop等图像处理工具直接为图片本身添加阴影效果,而非全交给CSS样式去处理。

例如,页面的顶部有一个固定区域的header标头,若它与页面其他位置的某个区域位于同一图层,当后者发生重绘时,就有可能触发包括固定标头区域在内的整个页面的重绘。对于固定不变不期望发生重绘的区域,建议可将其提升为独立的绘图层,避免被其他区域的重绘连带着触发重绘。

5、合成处理

合成处理是将已绘制的不同图层放在一起,最终在屏幕上渲染出来的过程。在这个环节中,有两个因素可能会影响页面性能:一个是所需合成的图层数量,另一个是实现动画的相关属性。

可通过将固定区域和动画区域拆分到不同图层上进行绘制,来达到绘制区域最小化的目的。接下来我们就来探讨如何创建新的图层,最佳方式便是使用CSS属性will-change来创建:

在这里插入图片描述

该方法在Chrome、Firefox及Opera上均有效,而对于Safari等不支持will-change属性的浏览器,则可以使用3D变换来强制创建:

在这里插入图片描述

虽然创建新的图层能够在一定程度上减少绘制区域,但也应当注意不能创建太多的图层,因为每个图层都需要浏览器为其分配内存及管理开销。如果已经将一个元素提升到所创建的新图层上,也最好使用Chrome开发者工具中的Layers对图层详情进行评估,确定是否真的带来了性能提升,切忌在未经分析评估前就盲目地进行图层创建。

仅合成相关的动画属性

如果一个动画的实现不经过页面布局和重绘环节,仅在合成处理阶段就能完成,则将会节省大量的性能开销。目前能够符合这一要求的动画属性只有两个:透明度opacity和图层变换transform。它们所能实现的动画效果如表所示,其中用n来表示数字。

在这里插入图片描述

在使用opacity和transform实现相应的动画效果时,需要注意动画元素应当位于独立的绘图层上,以避免影响其他绘制区域。这就需要将动画元素提升至一个新的绘图层。

6、服务器端渲染

对于数据相关的页面,比如用户中心的例子,需要获取到与用户相关的数据后再去进行编译和渲染,对此可以考虑将这些步骤放在服务器端去执行。

能这么做的原因是,首先数据获取本身就需要向服务器端发起请求,这一步服务器端具有天然的优势,其次服务器端的nodejs与浏览器同样都使用JavaScript语言,这就使得服务器端能在获取到数据后,就去执行Vue核心代码进行编译及渲染,从而生成可在浏览器端直接渲染的HTML文件。当然这个HTML文件最终还需要在浏览器端与Vue框架进行混入,让Vue框架来管理相应的数据。

这就是所谓的服务器端渲染,简单说就是将原本在客户端执行的与首屏渲染相关JavaScript处理逻辑,移到服务器端进行处理。

这样做虽然可以减少等待Vue框架加载与执行的时间,但会增加服务器的算力压力,同时也有可能面临服务器端内存泄漏的风险。可是考虑到服务器端集群的运算能力,肯定会高于用户端单个手机或电脑等设备上浏览器的运算能力,所以在有限的页面上,采取服务器端渲染能够明显提升首屏页面的渲染速度,同时在具体使用的页面范围上,也应当参考运算能力平衡考虑。

在这里插入图片描述

Vue 服务器端渲染

由于Vue组件生命周期在服务器端和在客户端上不一致,因此需要针对服务器端渲染编写相应的组件代码。

比如Vue组件在进行服务器端渲染的时候,不存在真实DOM节点渲染的情况,所以并不存在mounted这个生命周期函数,那么原本在客户端编写的组件,就需要将mounted中的业务逻辑迁移到组件的其他位置上。

接着往右看,业务源代码从app.js处分出了两个构建入口,webpack会根据不同的入口配置,分别生成用于服务器端渲染所需的Server Bundle和客户端渲染所需的Client Bundle。其中Server Bundle会在所定义的包渲染器中,被编译生成可以在浏览器端直接进行渲染的HTML文件。

这里还存在一个小问题:由于这份服务器端渲染所得的HTML文件,也是由Vue组件和相应的数据生成的,其包含的数据到了客户端之后,还是需要通过浏览器端的Vue框架进行管理的。

Vue 的 SSR 项目实例

一个demo的目录结构如下:

在这里插入图片描述

build下存放与项目构建相关的配置文件,

public中存放着项目中用到的一些静态资源文件,

dist存放着工程构建打包的输出文件,

src目录下为项目的主要源代码文件,

可以看出这是一个基于Vue的典型前端项目。

其中包含了组建目录components、路由设置router、基于Vuex状态管理的store、页面视图views及相应的入口文件。接下来将对该Vue项目的服务器端渲染过程进行简要介绍。

1、服务器端渲染所返回的 HTML 文件

服务器端渲染的目的是为浏览器返回一个可供直接进行绘制的HTML文件,从而减少首屏出现的时间,在该项目中文件index.template.html即为最终所要生成的服务器端渲染结果的模板文件,其内容如下:

在这里插入图片描述

在head标签中包含了title、显示设置、样式文件及一些预加载和预获取的文件配置,而在body标签中则通过注释的方式(vue-ssr-oulet)标定出了服务器端渲染DOM所要注入的节点位置。

2、输出 HTML 文件的编译过程

明确了模板文件index.template.html的作用后,接下来我们分析该模板文件如何处理并最终生成给浏览器直接渲染的HTML文件,这个过程必定是通过webpack构建完成的,可在配置文件中搜索模板文件的文件名,在webpack.client.config.js中查到如下配置信息:

在这里插入图片描述

该配置插件HTMLPlugin的作用是编译入参中指定的模板文件,并在dist目录下生成最终所需的index.html文件。要追溯编译构建过程,可从启动项目的命令npm run dev开始查询服务器启动代码server.js,代码如下:

在这里插入图片描述

这里是服务器启动处理的一个中间环节,

一方面开发环境下更具体的处理流程在/build/setup-dev-server.js文件中进行,在其中会启动一个开发调试用的服务器;

另一方面当文件修改发生后,会调用createRenderer方法生成服务器返回给浏览器的HTML文件中的内容字符串。

在服务器启动环节中的主要操作分别根据webpack.client.config.js和webpack.server.config.js的配置文件构建打包出Client Bundle和Server Bundle,其中处理Server Bundle的代码如下:

在这里插入图片描述

3、服务器端渲染方法

createRenderer方法代码如下:

在这里插入图片描述

通过createBundleRenderer方法可根据上一步构建生成的Server Bundle和模板配置选项共同生成一个BundleRenderer实例,该实例包含两个成员方法renderToString和renderToStream,它们分别可以将服务器渲染的内容以字符串和可读数据流的形式输出,输出结果即为浏览器请求首屏页面后服务器端返回可供直接渲染的结果。

可以看出该项目并非对所有页面都进行了服务器端渲染,它仅对首屏页面的顶部进行了服务器端渲染,下半部分的资源列表采用的是客户端渲染,因此能够根据实际的业务情况去平衡需要客户端渲染与服务器端渲染是十分必要的。

服务器端渲染大部分解决的应当是首屏性能问题。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

高等数学基础篇(数二)之二重积分

二重积分: 一、二重积分的概念及性质 1.二重积分的概念 2.二重积分的性质 二、二重积分的计算 1.利用直角坐标计算 2.利用极坐标计算 3.利用函数的奇偶性计算 4.利用变量的轮换对称性计算 目录 一、二重积分的概念及性质 1.二重积分的概念 2.二重积分的性…

Linux 常用指令及其理论知识

个人主页:仍有未知等待探索-CSDN博客 专题分栏:http://t.csdnimg.cn/Tvyou 欢迎各位指教!!! 目录 一、理论知识 二、基础指令 1、ls指令(列出该目录下的所有子目录和文件) 语法: …

学习vue3第十四节 Teleport 内置组件介绍

<Teleport></Teleport> 作用目的&#xff1a; 用于将指定的组件或者元素传送到指定的位置&#xff1b; 通常是自定义的全局通用弹窗&#xff0c;绑定到 body 上&#xff0c;而不是在当前元素上面&#xff1b; 使用方法&#xff1a; 接收两个参数 to: 要将目标传…

刷题日记——机试(1)

1. 字母排序 分析——不排序解题 创建一个大小为128的数组sheet&#xff0c;序号表示ascii码强转为int表示的数值&#xff0c;对应的数组值表示该ascii码在输入字符串中出现的次数设置一个max变量和id变量&#xff0c;max初值为0&#xff0c;从下标为((int)‘A’)开始遍历shee…

考研数学|汤家凤《1800》题太多!怎么刷效果最好?

考研数学三的备考过程中&#xff0c;汤家凤1800题是很多考生选择的一本重要的习题集。它包含了大量的题目&#xff0c;难度覆盖了从基础到提高&#xff0c;甚至有一些题目的难度会超过实际考试的平均水平&#xff0c;目的是为了帮助考生全面提升解题能力&#xff0c;尤其是在应…

Golang | Leetcode Golang题解之第11题盛最多水的容器

题目&#xff1a; 题解&#xff1a; func maxArea(height []int) int {res : 0L : 0R : len(height) - 1for L < R {tmp : math.Min(float64(height[L]), float64(height[R]))res int(math.Max(float64(res), tmp * float64((R - L))))if height[L] < height[R] {L} el…

代码+视频,手动绘制logistic回归预测模型校准曲线(Calibration curve)(2)

校准曲线图表示的是预测值和实际值的差距&#xff0c;作为预测模型的重要部分&#xff0c;目前很多函数能绘制校准曲线。 一般分为两种&#xff0c;一种是通过Hosmer-Lemeshow检验&#xff0c;把P值分为10等分&#xff0c;求出每等分的预测值和实际值的差距 另外一种是calibrat…

扫描电镜如何能拍到样品的好的形貌?

扫描电镜是表征材料微观形貌的有力工具&#xff0c;它能够呈现样品的精细结构。然而&#xff0c;要拍摄出高质量的样品形貌并非易事&#xff0c;除了要熟悉扫描电镜的各种功能&#xff0c;还需要掌握一些技巧。本文将介绍如何利用景深、倾斜校正、动态聚焦等功能以及合轴和消像…

Day30 线程安全之窗口售票问题(含代码)

Day30 线程安全之窗口售票问题&#xff08;含代码&#xff09; 一、需求&#xff1a; 铁道部发布了一个售票任务&#xff0c;要求销售1000张票&#xff0c;要求有3个窗口来进行销售&#xff0c; 请编写多线程程序来模拟这个效果&#xff08; 注意&#xff1a;使用线程类的方式…

LABVIEW--正弦+高斯噪声信号及滤波

前面板信号 后面板 LABVIEW源程序链接&#xff1a;https://pan.baidu.com/s/11B-75i4fHZwWQyjxn9yCyQ?pwd7tfj 提取码&#xff1a;7tfj

设计模式之建造者模式:灵活可扩展的对象创建过程

目录 一、什么是建造者模式 二、建造者模式的应用场景 三、建造者模式的优缺点 3.1. 优点 3.2. 缺点 四、建造者模式示例 4.1. 问题描述 4.2. 问题分析 4.3. 代码实现 五、建造者模式的另一种实现方式 六、总结 一、什么是建造者模式 建造者模式&#xff08;Builder…

WEBAPIS知识案例总结(续)

其他事件 页面加载事件 加载外部资源&#xff08;如图片&#xff0c;外联css和js等&#xff09;加载完毕时触发的事件有时候需要等页面资源全部处理完之后做一些事情老代码喜欢把script写在head中&#xff0c;这时候直接找dom元素找不到事件名&#xff1a;load监听页面所有资…

【热门话题】Stable Diffusion:本地部署教程

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 Stable Diffusion&#xff1a;本地部署教程一、引言二、环境准备1. 硬件配置2. …

考研数学|怎样刷题更有效率?这些坑千万别踩!

考研数学刷题的这些困扰相信大部分的同学都是有的&#xff0c;为此我整理了一些提高考研数学刷题效率的方法和策略&#xff0c;希望能帮助你更有效地学习和解题。 首先要制定合理的刷题计划&#xff0c;首先遵循“教材→视频→全书或辅导讲义→习题集→真题→专项训练→模拟套…

vue项目开发实战案例

目录 项目概述 1. 项目初始化 2. 商品展示 3. 购物车管理 4. 订单处理 5. 路由管理 6. 样式和交互优化 7. 部署和测试 总结 Vue.js 是一种流行的前端 JavaScript 框架&#xff0c;广泛应用于现代 Web 开发中。下面是一个简单的 Vue 项目开发实战案例&#xff0c;涵盖了…

C++的并发世界(七)——互斥锁

0.死锁的由来 假设有两个线程T1和T2&#xff0c;它们需要对两个互斥量mtx1和mtx2进行访问。而且需要按照以下顺序获取互斥量的所有权&#xff1a; -T1先获取mte1的所有权,再获取mt2的所有权。 -T2先获取 mtx2的所有权。再铁取 mtx1的所有权。 如果两个线程同时执行&#xff0c…

Redis主从复制、哨兵模式、Cluster集群

目录 一、Redis主从复制 1、主从复制介绍 2、主从复制原理 ​编辑 3、主从复制的作用 4.Redis主从复制实验搭建 1. 关闭防火墙和安装依赖环境 2. 解压安装包 3. 编译并安装到指定目录 4. 执行脚本文件 5. 做软连接 6. 启动redis并查看端口 7. 重启redis 8. 修改主…

秋招刷题4(动态规划)

1.购物单 import java.util.Scanner;public class Main {public static void main(String[] args){Scanner sc new Scanner(System.in);int N sc.nextInt();int m sc.nextInt();Goods[] goods new Goods[m];for(int i 0; i < m; i){goods[i] new Goods();}for(int i …

Matlab|含氢微网优化调度模型

目录 1 主要内容 模型示意图 目标函数 2 部分程序 3 程序结果 4 下载链接 1 主要内容 最近咨询含氢微网优化调度模型的同学较多&#xff0c;本次就分享一个高质量的源码资源。该程序方法复现《Simulation of design and operation of hydrogen energy utilization system…

数据生成 | Matlab实现基于K-means和SVM的GMM高斯混合分布的数据生成

数据生成 | Matlab实现基于K-means和SVM的GMM高斯混合分布的数据生成 目录 数据生成 | Matlab实现基于K-means和SVM的GMM高斯混合分布的数据生成生成效果基本描述模型描述程序设计参考资料 生成效果 基本描述 1.Matlab实现基于K-means和SVM的GMM高斯混合分布的数据生成&#xf…